KNN程式碼分析 - 之(1)相親決策
KNN的全稱是k- Nearest Neighbors. 在資料中找到最接近的資料,然後根據剩下的k個數據做選擇。 怎麼測量A資料和B資料是否接近方面,我們用到了測量資料距離的公式,Euclidian:
例如計算點(0,0) 和點(1,2)的距離就是:
假設,你就是在相親網站註冊了你,你平時在選擇是否覺得與女嘉賓出來約會是,總有些考量,比如,身高,年齡,長相,體重等。等你選擇了多個你覺得會出去約會的女嘉賓,程式碼就對新來的女嘉賓,做個預測,找的你之前選擇這些特徵最為接近的K個女嘉賓。做出決策
def classify0(inX, dataSet, labels, k):
# getting the rows of the dataset.
dataSetSize = dataSet.shape[0]
# tile the second parameter means tile shape
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
sqDiffMat = diffMat ** 2
# This axis = 1 mean sum the row of data
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances ** 0.5
# example: x=np.array([1,4,3,-1,6,9])
# y=array([3,0,2,1,4,5])
sortedDistIndicies = distances.argsort()
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
# P
# dict = {'Name': 'Zara', 'Age': 27}
# print "Value : %s" % dict.get('Age')
# print "Value : %s" % dict.get('Sex', "Never")
# Value : 27 Value : Never
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
這片段程式碼摘自Machin Learning In Action.
我們這裡就以這片段做分析。已相親節目為例子,它是怎麼完成對於新來相親嘉賓,根據她(他)的基本資訊如,身高,體重,長相…來判斷他(她)是否喜歡的型別。
def classify0(inX, dataSet, labels, k):
有四個引數:
第一個inX,一組樣本用例。例如相親節目中對【身高,體重,收入】比較重視,也就是這組資料是【170cm, 60kg, 1000~2000收入】
第二個dataSet, 採集到所以對於相親物件的身高,體重,收入等資料。
第三個Labels,這標記樣本資料,如,在一組資料中【身高,體重,收入】他滿意這類相親物件那標記為1, 不滿意為0
第四個引數K, 就是比對K個人的相關資訊,比如,這些相似的相親資料中,他選擇的偏好是哪些。
dataSetSize = dataSet.shape[0]
這個是獲得樣本的條數,比如收集到的100個相親物件資訊,對應的dataSetSize就是100.
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
這行就是計算其中一條樣例與其他物件的差值。其中需要強調的是tile. 在英語中
tile指的是瓷磚,做動詞就是鋪瓷磚。《老友記》第8季,第七集中,女傭很喜歡Manica的清潔劑就說到:Mrs Bing, this tile cleaner is in credible. 這就是其中的tile. 回到程式碼,tile就相當我們把inX,平鋪出去,怎麼鋪呢?按照(dataSetSize,1)的大小平鋪。在相親為例子的中,我們得到一個女孩的中比較重要的資訊,如【身高,體重,年齡,長相】等等,給她tile出去,就是把這個女孩的資訊複製出去,複製出來的條數跟dataSet的條數一樣的。然後在減掉dataSet的資料。得到diffMat這種差值資料集合。
sqDiffMat = diffMat ** 2
這行就是對這差值求平方。為什麼這麼做,運用的是數學中的卡達爾公式,求兩點之間的距離。
sqDistances = sqDiffMat.sum(axis=1)
這個是對矩陣中的行進行相加,axis 是最關鍵的引數,表示維度。如其中一個人的資訊,與別人比對完之後,彙總起來。前幾天剛看了《非誠勿擾》的節目,其中兩個女孩的陳東源,和陳子涵的身高,年齡都很象,她們兩個女孩都對那男孩子感興趣。那男孩子改選誰呢?
distances = sqDistances ** 0.5
這個在對值求平方根,是公式的一部分,不做重點強調,強調的是**的意思就是求數值的指數冪。
sortedDistIndicies = distances.argsort()
這行執行程式碼時的重點,也是難點,就是它的還回值到底是什麼呢?它還回從小到大數值對應的Index. 比較拗口,舉個例子:distances =[5,3,9,4] , 它對於從小到大應該是[3,4,5,9], 那3是在位置1,5在位置0,所以輸出結果應該是[1,3,0,2],建議自己去實驗下。
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
# P
# dict = {'Name': 'Zara', 'Age': 27}
# print "Value : %s" % dict.get('Age')
# print "Value : %s" % dict.get('Sex', "Never")
# Value : 27 Value : Never
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
這片段中的get對我來說非常重要。總結下get用法:
在《老友記》第八季第七集中,女傭看見Manica清潔劑很好用,後面補充到:“How did you get it?” 這裡get就是,得到,買到意思。
在《泰坦尼克號》電影中,Rose在甲板上問Jone:“You do get around for poor guy?” 這裡的get就是“動身”,身體發出的動作。
在《穿普拉達的女王》電影中,女主角氣氛的對男朋友說:“But I can’t let Miranda get to me” 我不想讓Miranda影響到我,這裡的get,是收到影響。
我們這程式碼中get是什麼意思呢?當然就是第一種情況,在字典{}中得到它的值,如果沒值的話,預設為0.
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0]
[0]