机器学习实战学习笔记(二)-KNN算法(2)-KNN算法改进约会网站的配对效果

老子叫甜甜 提交于 2020-01-22 23:14:47

机器学习实战学习笔记(二)-KNN算法(2)-KNN算法改进约会网站的配对效果

情景概要

某个妹子交往过三种类型的人:

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

这个妹子想要知道自己到底喜欢哪一类男人,于是提供了她收集的约会数据(1000行,吐槽一波,手动狗头),并希望能创建一种分类机制来帮她完成这件事情。

数据表格如下:

实际数据集是这样的:

datingTestSet.txt

datingTestSet2.txt

导入数据

# 判断分类
def isWhichClass(className):
    if className=='didntLike':
        return 1
    elif className=='smallDoses':
        return 2
    elif className=='largeDoses':
        return 3

#加载数据

def file2matrix(filename):
    fr=open(filename)
    arrayOLines=fr.readlines()
    numbersOfLines=len(arrayOLines)#获取一共有多少行
    returnMat=np.zeros((numbersOfLines,3))#创建n行3列的全零矩阵
    classLabelVector=[]#标签向量
    index=0
    for line in arrayOLines:
        line=line.strip()
        listFormLine=line.split('\t')
        returnMat[index,:]=listFormLine[0:3]
        classLabelVector.append(isWhichClass(listFormLine[-1]))
        index+=1
    return returnMat,classLabelVector

数据可视化

#绘图
def makeGraph():
    returnMat,classLabelVector=file2matrix('KNN\datingTestSet.txt')
    fig=plt.figure()
    ax=fig.add_subplot(111)
    x1=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==1]
    y1=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==1]
    x2=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==2]
    y2=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==2]
    x3=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==3]
    y3=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==3]
    type1=plt.scatter(x1,y1,c="red",cmap='brg',alpha=0.2, marker='8', linewidth=0)
    type2=plt.scatter(x2,y2,c="green",cmap='brg',alpha=0.2, marker='8', linewidth=0)
    type3=plt.scatter(x3,y3,c="blue",cmap='brg', alpha=0.2, marker='8', linewidth=0)
    ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
    mpl.rcParams['font.sans-serif']=['SimHei'] #指定默认字体 SimHei为黑体
    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
    plt.xlabel('玩游戏时间所占百分比', fontsize=14)
    plt.ylabel('每周消耗的冰激凌的公斤数', fontsize=14)
    plt.show()

归一化数据

原理:

为什么要归一化?

数字差值最大的属性对计算结果的影响最大,也就是说,但这三种特征是同等重要的,因此要归一化

归一化方法

在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围
处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:

newvalue=(o1dValue -min) / (max- min)

其中min和max分别是数据集中的最小特征值和最大特征值。

# 自动归一化
def autoNorm(dataSet):
    minVal=dataSet.min(0)
    maxVal=dataSet.max(0)
    ranges=maxVal-minVal
    normDataSet=np.zeros(np.shape(dataSet))
    m=dataSet.shape[0]
    normDataSet=dataSet-np.tile(minVal,(m,1))
    normDataSet=normDataSet/np.tile(ranges,(m,1))
    return normDataSet,ranges,minVal

测试分类效果

#测试数据
def datingAllClassTest():
    hoRatio = 0.10      #测试集数量比例
    datingDataMat,datingLabels = file2matrix("KNN\datingTestSet.txt")     #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]#总样本数
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult=knnClassify(normMat[i,:],normMat[numTestVecs:m,:],datingLabels,3)
        print("预测的结果是%d 真正的答案是%d"%(classifierResult,datingLabels[i]))
        if classifierResult!=datingLabels[i]:
            errorCount+=1
    print("总的正确率是 %f"%(errorCount/float(numTestVecs)))
    print("错误数量是 %d"%errorCount)

实际应用作为分类器

#使用数据判断妹子是否喜欢你
def datingClassTest():
    resultList = ['妹子不喜欢你', '妹子有点喜欢你', '妹子特别喜欢你']
    ffMiles=float(input("你一年坐的飞机飞多少里:"))
    iceCream=float(input("你一年吃多少冰激凌?"))
    gameTime=float(input("你一年打多少小时的游戏?"))
    inArr=np.array([ffMiles,gameTime,iceCream])
    resDataMatrix,labels=file2matrix("KNN\datingTestSet.txt")
    normData,ranges,minVal=autoNorm(resDataMatrix)
    classResult=knnClassify((inArr-minVal)/ranges,normData,labels,3)
    print("估计是%s"%(resultList[classResult-1]))

源代码

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib as mpl
import operator as op
# 判断分类
def isWhichClass(className):
    if className=='didntLike':
        return 1
    elif className=='smallDoses':
        return 2
    elif className=='largeDoses':
        return 3

#加载数据

def file2matrix(filename):
    fr=open(filename)
    arrayOLines=fr.readlines()
    numbersOfLines=len(arrayOLines)#获取一共有多少行
    returnMat=np.zeros((numbersOfLines,3))#创建n行3列的全零矩阵
    classLabelVector=[]#标签向量
    index=0
    for line in arrayOLines:
        line=line.strip()
        listFormLine=line.split('\t')
        returnMat[index,:]=listFormLine[0:3]
        classLabelVector.append(isWhichClass(listFormLine[-1]))
        index+=1
    return returnMat,classLabelVector


def file3matrix(filename):
    fr=open(filename)
    arrayOLines=fr.readlines()
    numbersOfLines=len(arrayOLines)#获取一共有多少行
    returnMat=np.zeros((numbersOfLines,3))#创建n行3列的全零矩阵
    classLabelVector=[]#标签向量
    index=0
    for line in arrayOLines:
        line=line.strip()
        listFormLine=line.split('\t')
        returnMat[index,:]=listFormLine[0:3]
        classLabelVector.append(int(listFormLine[-1]))
        index+=1
    return returnMat,classLabelVector

#绘图
def makeGraph():
    returnMat,classLabelVector=file2matrix('KNN\datingTestSet.txt')
    fig=plt.figure()
    ax=fig.add_subplot(111)
    x1=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==1]
    y1=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==1]
    x2=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==2]
    y2=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==2]
    x3=[x[1] for i,x in enumerate(returnMat) if classLabelVector[i]==3]
    y3=[x[2] for i,x in enumerate(returnMat) if classLabelVector[i]==3]
    type1=plt.scatter(x1,y1,c="red",cmap='brg',alpha=0.2, marker='8', linewidth=0)
    type2=plt.scatter(x2,y2,c="green",cmap='brg',alpha=0.2, marker='8', linewidth=0)
    type3=plt.scatter(x3,y3,c="blue",cmap='brg', alpha=0.2, marker='8', linewidth=0)
    ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2)
    mpl.rcParams['font.sans-serif']=['SimHei'] #指定默认字体 SimHei为黑体
    mpl.rcParams['axes.unicode_minus']=False #用来正常显示负号
    plt.xlabel('玩游戏时间所占百分比', fontsize=14)
    plt.ylabel('每周消耗的冰激凌的公斤数', fontsize=14)
    plt.show()

#K近邻算法
#inX是输入的数据
#dataSet是训练的数据
#labels是标签,类别
#k是周围邻居的数量
#返回预测的类别
def knnClassify(inX,dataSet,labels,k):
    #计算欧式距离
    dataSetSize=dataSet.shape[0]#shape是(4,2),要获取点的数量显然是shape[0]
    diffMat=np.tile(inX,(dataSetSize,1))-dataSet
    '''
    np.tile(inX,(dataSetSize,1))=[[0,0],[0,0],[0,0],[0,0]]
    dataSet=[[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]
    np.tile-dataSet=[[-1.0,-1.1],[-1.0,-1.0],[0,0],[0,-0.1]]
    即([x1-x0,y1-y0],[x2-x0,y2-x0],[x3-x0,y3-y0],[x4-x0,y4-y0])
    '''
    sqdiffMat=diffMat**2
    #([(x1-x0)**2,(y1-y0)**2],[(x2-x0)**2,(y2-x0)**2],[(x3-x0)**2,(y3-y0)**2],[(x4-x0)**2,(y4-y0)**2])
    sqDistances=sqdiffMat.sum(axis=1)
    #([(x1-x0)**2+y1-y0)**2],[(x2-x0)**2+(y2-x0)**2],[(x3-x0)**2+(y3-y0)**2],[(x4-x0)**2+(y4-y0)**2])
    # print(sqDistances)
    distances=sqDistances**0.5
    #([(x1-x0)**2+(y1-y0)**2]**(0.5),[(x2-x0)**2+(y2-x0)**2]**(0.5),[(x3-x0)**2+(y3-y0)**2]**(0.5),[(x4-x0)**2+(y4-y0)**2])**(0.5)
    sortedDistIndicies=distances.argsort()#按照数值大小对下标排序,[2 3 1 0]
    classCount={}
    #选择距离最小的k个点
    for i in range(k):
        votIlabel=labels[sortedDistIndicies[i]]#获取最近的K个邻居的距离,对应的目标值
        # print(votIlabel)
        classCount[votIlabel]=classCount.get(votIlabel,0)+1#get(key,default)当key不存在时候默认值是default
    sortedClassCount = sorted(classCount.items(), key=op.itemgetter(1), reverse=True)
    # [('B', 2), ('A', 1)]
    return sortedClassCount[0][0]#返回与其最近的k个邻居中,出现最多的次数

# 自动归一化
def autoNorm(dataSet):
    minVal=dataSet.min(0)
    maxVal=dataSet.max(0)
    ranges=maxVal-minVal
    normDataSet=np.zeros(np.shape(dataSet))
    m=dataSet.shape[0]
    normDataSet=dataSet-np.tile(minVal,(m,1))
    normDataSet=normDataSet/np.tile(ranges,(m,1))
    return normDataSet,ranges,minVal


#测试数据
def datingAllClassTest():
    hoRatio = 0.10      #hold out 10%
    datingDataMat,datingLabels = file2matrix("KNN\datingTestSet.txt")     #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult=knnClassify(normMat[i,:],normMat[numTestVecs:m,:],datingLabels,3)
        print("预测的结果是%d 真正的答案是%d"%(classifierResult,datingLabels[i]))
        if classifierResult!=datingLabels[i]:
            errorCount+=1
    print("总的正确率是 %f"%(errorCount/float(numTestVecs)))
    print("错误数量是 %d"%errorCount)

#使用数据判断妹子是否喜欢你
def datingClassTest():
    resultList = ['妹子不喜欢你', '妹子有点喜欢你', '妹子特别喜欢你']
    ffMiles=float(input("你一年坐的飞机飞多少里:"))
    iceCream=float(input("你一年吃多少冰激凌?"))
    gameTime=float(input("你一年打多少小时的游戏?"))
    inArr=np.array([ffMiles,gameTime,iceCream])
    resDataMatrix,labels=file2matrix("KNN\datingTestSet.txt")
    normData,ranges,minVal=autoNorm(resDataMatrix)
    classResult=knnClassify((inArr-minVal)/ranges,normData,labels,3)
    print("估计是%s"%(resultList[classResult-1]))
   

if __name__ == "__main__":
    datingClassTest()
    

目录结构

数据集

https://github.com/pbharrin/machinelearninginaction

参考书籍

《机器学习实战》-彼得·哈灵顿

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!