使用k-邻近算法改进约会网站的配对效果
首先要找数据出处,海伦约会数据放在文本文件datingTestSet.txt中,每个数据样本数据占据一行,总共有1000行。
下载网址:[http:/www.manning.com/MachineLearninginAction]
点击左侧Source Code
或者:http://www.ituring.com.cn/book/1021 点击右侧“随书下载”
准备数据:从文本文件中解析数据
#将文本记录到转换NumPy的解析程序
def file2matrix(filename):
fr=open(filename)
# 得到文本行数
arrayOLines=fr.readlines()
numberOfLines=len(arrayOLines)
returnMat=zeros((numberOfLines,3))
classLabelVector=[] #创建返回的Numpy库
index=0
for line in arrayOLines:
# 截取掉所有的回车字符
line = line.strip()
# 将上一行得到的整行数据分割成一个元素列表
listFromLine=line.split('\t') #解析文本数据到列表
# 取前3个数据
returnMat[index,:]=listFromLine[0:3]
# 将列表最后一列存储到向量classLabelVector中
classLabelVector.append(int(listFromLine[-1]))
index+=1
return returnMat,classLabelVector
Debug:
ValueError: invalid literal for int() with base 10: 'largeDoses'
书上示例datingTestSet.txt应改为datingTestSet2.txt
datingDataMat,datingLabels=KNN.file2matrix('datingTestSet.txt')改为datingDataMat,datingLabels=KNN.file2matrix('datingTestSet2.txt')
分析数据:使用Matplotlib创建散点图
>>> import matplotlib
>>> import matplotlib.pyplot as plt
>>> fig=plt.figure()
>>> ax=fig.add_subplot(111)
>>> ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
<matplotlib.collections.PathCollection object at 0x0000029E3B9C57F0>
>>> plt.show()
输出:
image.png
#coding: utf-8
from numpy import * #导入numpy包,这里要用到numpy中的array
from KNN import * #导入产生数据的包
import matplotlib #导入绘图的库
import matplotlib.pyplot as plt #将绘图的函数重命名
from mpl_toolkits.mplot3d import Axes3D #导入3维图像的包
plt.rcParams['font.sans-serif'] = ['FangSong'] # 指定字体为仿宋
plt.rcParams['axes.unicode_minus'] = False # 解决图像显示为方块的问题
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
fig1=plt.figure() #创建图形
#-------------------二维-----------
#第一个子图,是第2个特征和第3个特征的散点图 但是没有颜色标识
ax=fig1.add_subplot(2,2,1) #代表创建2行2列从上到下的第一块的子图
ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
plt.xlabel(u'x 玩视频游戏所消耗时间半分比')
plt.ylabel(u'y 每周消费的冰淇淋公升数')
plt.title(u'图一(2&&3)')
#定义三个类别的空列表
type1_x=[]
type1_y=[]
type2_x=[]
type2_y=[]
type3_x=[]
type3_y=[]
#第二个子图 是第2个特征和第3个特征的散点图
ax=fig1.add_subplot(2,2,2) #代表创建2行2列从上到下的第二块的子图
#循环获得每个列表中的值
for i in range(len(datingLabels)):
if datingLabels[i]==1: #不喜欢
type1_x.append(datingDataMat[i][1])
type1_y.append(datingDataMat[i][2])
if datingLabels[i]==2: #魅力一般
type2_x.append(datingDataMat[i][1])
type2_y.append(datingDataMat[i][2])
if datingLabels[i]==3: #极具魅力
type3_x.append(datingDataMat[i][1])
type3_y.append(datingDataMat[i][2])
type1=ax.scatter(type1_x,type1_y,s=20,c='red')
type2=ax.scatter(type2_x,type2_y,s=40,c='green')
type3=ax.scatter(type3_x,type3_y,s=50,c='blue')
ax.legend((type1,type2,type3),(u'不喜欢',u'魅力一般',u'极具魅力'),loc=2) #显示图例 1 右上 2 左上 3 左下 4 右下 逆时针
#ax.scatter(datingDataMat[:,0],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.xlabel(u'x 玩视频游戏所消耗时间半分比')
plt.ylabel(u'y 每周消费的冰淇淋公升数')
plt.title(u'图二(2&&3)')
#第三个子图 是第1个特征和第2个特征的散点图
ax=fig1.add_subplot(2,2,3) #代表创建2行2列从上到下的第三块的子图
#循环获得每个列表中的值
for i in range(len(datingLabels)):
if datingLabels[i]==1: #不喜欢
type1_x.append(datingDataMat[i][0])
type1_y.append(datingDataMat[i][1])
if datingLabels[i]==2: #魅力一般
type2_x.append(datingDataMat[i][0])
type2_y.append(datingDataMat[i][1])
if datingLabels[i]==3: #极具魅力
type3_x.append(datingDataMat[i][0])
type3_y.append(datingDataMat[i][1])
type1=ax.scatter(type1_x,type1_y,s=20,c='red')
type2=ax.scatter(type2_x,type2_y,s=40,c='green')
type3=ax.scatter(type3_x,type3_y,s=50,c='blue')
ax.legend((type1,type2,type3),(u'不喜欢',u'魅力一般',u'极具魅力'),loc=2) #显示图例 1 右上 2 左上 3 左下 4 右下 逆时针
#ax.scatter(datingDataMat[:,0],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.xlabel(u'x 每年获取的飞行常客里程数')
plt.ylabel(u'y 玩视频游戏所耗时间半分比')
plt.title(u'图三(1&&2)')
#第四个子图 是第1个特征和第3个特征的散点图
ax=fig1.add_subplot(2,2,4) #代表创建2行2列从上到下的第四块的子图
#循环获得每个列表中的值
for i in range(len(datingLabels)):
if datingLabels[i]==1: #不喜欢
type1_x.append(datingDataMat[i][0])
type1_y.append(datingDataMat[i][2])
if datingLabels[i]==2: #魅力一般
type2_x.append(datingDataMat[i][0])
type2_y.append(datingDataMat[i][2])
if datingLabels[i]==3: #极具魅力
type3_x.append(datingDataMat[i][0])
type3_y.append(datingDataMat[i][2])
type1=ax.scatter(type1_x,type1_y,s=20,c='red')
type2=ax.scatter(type2_x,type2_y,s=40,c='green')
type3=ax.scatter(type3_x,type3_y,s=50,c='blue')
ax.legend((type1,type2,type3),(u'不喜欢',u'魅力一般',u'极具魅力'),loc=2) #显示图例 1 右上 2 左上 3 左下 4 右下 逆时针
#ax.scatter(datingDataMat[:,0],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.xlabel(u"x 每年获取的飞行常客里程数")
plt.ylabel(u'y 每周消费的冰淇淋公升数')
plt.title(u'图四(1&&3)')
#------------三维-----------
fig2=plt.figure() #创建图形
ax=fig2.add_subplot(111)
ax=Axes3D(fig2)
ax.scatter(datingDataMat[:,0],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
ax.set_xlabel(u'x 每年获取的飞行常客里程数')
ax.set_ylabel(u'y 视频游戏所耗时间半分比')
ax.set_zlabel(u'z 每周消费的冰淇淋公升数')
plt.title(u'图四(1&&2&&3)')
plt.show()
Debug:绘图中坐标轴中文乱码问题
添加代码:
plt.rcParams['font.sans-serif'] = ['FangSong'] # 指定字体为仿宋
plt.rcParams['axes.unicode_minus'] = False # 解决图像显示为方块的问题
输出:
image.png
image.png
准备数据:归一化数值
归一化数值是为了不让某个特殊的属性对计算结果影响比较大,而应该每一个特征都是等权重的。
#归一化特征值
def autoNorm(dataSet):
#最小值放在minVals中,从列中选取最小值,而不是选取当前行的最小值
minVals=dataSet.min(0)
#最大值放在maxVals中
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
#检测函数输出结果
normMat,ranges,minVals=KNN.autoNorm(datingDataMat)
print(normMat)
print(ranges)
print(minVals)
Debug:<class 'range'>
autoNorm函数返回range改为ranges
输出:
[[0.44832535 0.39805139 0.56233353]
[0.15873259 0.34195467 0.98724416]
[0.28542943 0.06892523 0.47449629]
...
[0.29115949 0.50910294 0.51079493]
[0.52711097 0.43665451 0.4290048 ]
[0.47940793 0.3768091 0.78571804]]
[9.1273000e+04 2.0919349e+01 1.6943610e+00]
[0. 0. 0.001156]
测试算法
#分类器针对约会网站的测试代码
def datingClassTest():
hoRatio = 0.50 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.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 = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
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)))
print(errorCount)
#代码输出:
print(KNN.datingClassTest())
输出:
the classifier came back with: 3, the real answer is: 3
the classifier came back with: 2, the real answer is: 2
the classifier came back with: 1, the real answer is: 1
......
the classifier came back with: 1, the real answer is: 1
the classifier came back with: 2, the real answer is: 2
the total error rate is: 0.066000
使用算法:构建完整可用系统
#约会网站预测函数
def classifyPerson():
resultList=['not at all','in small doses','in large doses']
percentTats=float(input("percentage of time spent playing video games?"))
ffMiles=float(input("frequent flier miles earned per year?"))
iceCream=float(input("liters of ice cream consumed per year?"))
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
normMat,ranges,minVals=autoNorm(datingDataMat)
inArr=array([ffMiles,percentTats,iceCream])
classifierResult=classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
print("You will probably like this person: ",resultList[classifierResult -1] )
#输出结果:
print(KNN.classifyPerson())
输出:
percentage of time spent playing video games?10
frequent flier miles earned per year?10000
liters of ice cream consumed per year?0.5
You will probably like this person: in small doses
网友评论