KNN代码分析 - 之(1)《非诚勿扰》之喜好预测

本文通过《非诚勿扰》节目中嘉宾的选择行为,介绍了KNN算法在预测嘉宾偏好方面的应用。利用KNN算法,可以根据嘉宾历史选择的特征,如年龄、身高、体重和收入,预测新出现嘉宾是否会被划分为心动区或观察区。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看过《非诚勿扰》节目的朋友们都知道,节目开始有个选择心动区和观察区的环节。假设你是负责设计预测嘉宾偏好的程序员,我们将做个预测程序,根据嘉宾前面几次选择的女嘉宾,大致可以估算下下面出来的女嘉宾,他到底会不会喜欢。让我们开始吧。 首先简单介绍下算法, KNN的全称是k- Nearest Neighbors. 在数据中找到最接近的数据,然后根据剩下的k个数据做选择。 怎么测量A数据和B数据是否接近方面,我们用到了测量数据距离的公式,Euclidian:
d=(xA0−xB0)2+(xA1−xB1)d = \sqrt{(xA_0 -xB_0)^2 + (xA_1 - xB_1)} d=(xA0xB0)2+(xA1xB1)
例如计算点(0,0) 和点(1,2)的距离就是:
d=(0−1)2+(0−2)2d=\sqrt{(0-1)^2 + (0-2)^2}d=(01)2+(02)2

我们将出来的女嘉宾大致根据年龄,升高,体重,相貌做些基础的划分。
但因为相貌这个东西很难做量化。所以,我们把相貌替换成收入做参考比较。下面就是要实现的代码:

     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): 

def 是definition的简称。表示对函数的定义,对于这个词。看过《巨齿鲨》的朋友一定对小女孩不陌生。Jonas说自己不是疯子,只是看了别人没看到东西。她就对Jonas说:That’s the definnition of crazy. 就是这里的definition.
在这里插入图片描述

有四个参数:

第一个inX,一组样本用例。就是新上场的女嘉宾基本数据信息【身高,体重,收入】,如【170cm, 60kg, 1000~2000收入】

第二个dataSet, 采集到所有女嘉宾的身高,体重,收入等数据信息。

第三个Labels,这标记样本数据,就是前面男嘉宾之前几次选择标记为观察区,还是心动区的结果。我们将0代表观察区,1表示心动区

第四个参数K, 就是比对K个人的相关信息,参考最为接近的K个女孩他是把她划入观察区还是心动区。

 dataSetSize = dataSet.shape[0] 

这个是获得样本的条数,这里就是获得男嘉宾已经对女嘉宾选好了的数据条数,当然,在非诚勿扰中,一次只能选择12个女嘉宾,但对于程序来说,如果能有更多的女嘉宾选择的话,对于数据的准确度,会有所提高。

diffMat = tile(inX, (dataSetSize, 1)) - dataSet

这行就是计算其中一条样例与其他对象的差值。其中需要强调的是tile. 在英语中tile指的是瓷砖,做动词就是平铺。
《老友记》第8季,第七集中,女佣很喜欢Manica的清洁剂就说到:Mrs Bing, this tile cleaner is in credible. 这就是其中的tile.
在这里插入图片描述回到代码,假设现在男嘉宾已经选择好了9女嘉宾到底是在观察区还是心动区,现在新上来第10为女嘉宾。让我们做预测,我就用tile把这第10位女嘉宾复制9份,然后减掉前面9位女嘉宾的dataSet数据。得到diffMat这种差值数据集合。

sqDiffMat = diffMat ** 2

这行就是对这差值求平方。为什么这么做,我们会想新上场的女孩,可能跟前面一两个个女孩的身高有些接近,但不管是比前面高一点,还是矮一点都无所谓,我们只要接近的,所以用平方去除掉可能存在的负数。

sqDistances = sqDiffMat.sum(axis=1)

这个是对矩阵中的行进行相加,axis 是最关键的参数,表示维度。我们这里就是把所以对应的差值全部加起来,得到新上场的女嘉宾跟所有其他已经被选择好的女嘉宾之间差距的得分。

 distances = sqDistances ** 0.5 

这个在对值求平方根,是公式的一部分,不做重点强调,强调的是**的意思就是求数值的指数幂。

sortedDistIndicies = distances.argsort()

这行运行代码时的重点,也是难点,就是它的还回值到底是什么呢?
这里distances. 已经找的了第10个女孩和前面9个人的差距值,那我们要排序找到差距最小到最大的值。得到sortedDistIndicies这个值对应的序列号,如距离值为[5,2,3,1,0] 那差距最小的应该是0,0是在第4位,所以sortedDistIndicies的第一个值是4,差距第二小的是1,他是在第3位,所以,第二个值是3…得到[4,3,1,2,0]

    classCount = {}

这里创建一个字典,存储跟新上台女嘉宾最为接近的K个人的划分结果。

    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用法:

1.《老友记》第八季第七集中,女佣看见Manica清洁剂很好用,后面补充到:“How did you get it?” 这里get就是,得到,买到意思。
2. 《泰坦尼克号》电影中,Rose在甲板上问Jone:“You do get around for a poor guy?” 这里的get就是“动身”,身体发出的动作。
3. 《穿普拉达的女王》电影中,女主角气愤的对男朋友说:“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]

后文待续。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值