1. 程式人生 > >KNN程式碼分析 - 之(1)相親決策

KNN程式碼分析 - 之(1)相親決策

KNN的全稱是k- Nearest Neighbors. 在資料中找到最接近的資料,然後根據剩下的k個數據做選擇。 怎麼測量A資料和B資料是否接近方面,我們用到了測量資料距離的公式,Euclidian:
d = ( x A

0 x B 0 ) 2
+ ( x A 1 x
B 1 ) d = \sqrt{(xA_0 -xB_0)^2 + (xA_1 - xB_1)}
例如計算點(0,0) 和點(1,2)的距離就是:
d = ( 0 1 ) 2 + ( 0 2 ) 2 d=\sqrt{(0-1)^2 + (0-2)^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]