情景概要
某个妹子交往过三种类型的人:
不喜欢的人
魅力一般的人.
极具魅力的人
这个妹子想要知道自己到底喜欢哪一类男人, 于是提供了她收集的约会数据 (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()
目录结构
数据集
参考书籍
《机器学习实战》- 彼得. 哈灵顿
来源: http://www.bubuko.com/infodetail-3392798.html