机器学习实战学习笔记(二)-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
参考书籍
《机器学习实战》-彼得·哈灵顿