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]

猜你喜欢

转载自blog.csdn.net/xctcchenyong/article/details/85260092