机器学习实战--k近邻算法改进约会网站的配对效果

声明

        本文参考了《机器学习实战》书中代码,结合该书讲解,并加之自己的理解和阐述

问题描述

        朋友海伦一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她并不是喜欢每一个人。经过一番总结,她发现曾交往过三种类型的人:

  • 不喜欢的人
  • 魅力一般的人
  •  极具魅力的人

        为了让软件更好的给海伦推荐人选,海伦收集很多约会数据,她把这些数据存放在文本文件datingTestSet.txt中,每
个样本数据占据一行,总共有1000行。海伦的样本主要包含以下3种特征:

  • 每年获得的飞行常客里程数
  • 玩视频游戏所耗时间百分比
  • 每周消费的冰淇淋公升数

        接下来的任务就是判定一个人对海伦来说是否有魅力

K近邻算法

        该算法就是在一堆数据中找到与当前点最相似的K个点,然后由这K个点决定当前点属于哪一类,对未知类别属性的数据集中的每个点依次执行以下操作:

  1. 计算已知类别数据集中的点与当前点之间的距离;
  2. 按照距离递增次序排序;
  3. 选取与当前点距离最小的k个点;
  4. 确定前k个点所在类别的出现频率;
  5. 返回前k个点出现频率最高的类别作为当前点的预测分类。
     

代码实现

def classify0(inX,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
    #当前点与数据集做差
    diffMat = tile(inX,(dataSetSize,1))-dataSet
    # 求距离
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances**0.5
    sortedDistIndices = distances.argsort()
    classCount = {}
    #选取最近的K个点
    for i in range(k):
        voteIlabel = labels[sortedDistIndices[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回相似度最高的标签
    return sortedClassCount[0][0]

优化约会网站

        首先要读取海伦收集到的信息

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    returnMat = zeros((numberOfLines,3))
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat,classLabelVector

        然后我们会可视化的看一下三个维度的关系

returnMat,classLabelVector = file2matrix("datingTestSet.txt")
fig = plt.figure()
ax = fig.add_subplot(111)
#第1维与第2维
ax.scatter(returnMat[:,1],returnMat[:,2],15.0*array(classLabelVector),15.0*array(classLabelVector))
plt.show()

        然后会看到下图所示的图像,很明显竖直上没有区分信息,水平上有,那说明第一维信息有可能是有区分度的

        再看一下第0维和第1维的图像如下,发现区分情况较好

        当然我们还可以再看一看第0维和第2维的

        所以从图像上边也可以看出来,第2维的区分度确实很小,当然这些判断只是我们人为做出的数据分析,其实实际算法是可以不考虑这些的,因为不相干的信息并不影响最后结果。

下边要对数据做出归一化

def autoNorm(dataSet):
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals-minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet-tile(minVals,(m,1))
    normDataSet = normDataSet/tile(ranges,(m,1))
    return normDataSet,ranges,minVals

然后进行验证

def datingClassTest():
    hoRatio = 0.10
    datingDataMat,datingLabels = file2matrix("datingTestSet.txt")
    normMat,ranges,minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    #选取前numTestVecs做测试,训练集就是numTestVecs+1到最后的数据
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],
                                     datingLabels[numTestVecs:m],7)
        print("The classifier came back with %d,the real answer is: %d"
              %(classifierResult,datingLabels[i]))
        if(classifierResult!=datingLabels[i]):errorCount += 1.0
    print("The total error rate is:%f"%(errorCount/float(numTestVecs)))

结果展示

        这里k=7,原文中使用k=3失误率只有2.4%,而我发现只有当k取7时错误率最低只能降到4%

发布了55 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41685265/article/details/105196240