代码来自于《机器学习实战》
问题背景
小红经常在约会网站寻找适合自己的约会对象.经过自己的总结,发现曾经交往过三种类型的人:
不喜欢的人
魅力一般的人
极具魅力的人
发现了上述规律,小红还是无法将约会网站推荐的匹配对象归到恰当的类别.她希望在周一到周五约会那些魅力一般的人,周末想那些极具魅力的人为伴(世界一直围绕着小红在转啊转......).我们怎么帮助她?
1. 数据处理
数据保存在 datingTestSet2.txt 中,每个样本占据一行,共有 1000 行(哇,人才).样本主要包含以下 3 个特征:
每月工资
玩游戏所消耗时间百分比
每周消费的冰淇淋公升数
些许样例示意图
A 处理数据:将文本中的数据变成分类器能接受的格式.
导入需要的工具包
from numpy import *
定义函数 file2Matrix:将文本数据转换成矩阵形式
B 数据归一化处理
def file2Matrix(filename):
fr= open(filename)
arrayOLines= fr.readlines()# 直接将数据全部读取进来,形成列表,每一行为一个元素
numberOfLines= len(arrayOLines)# 行数
returnMatrix= zeros((numberOfLines,3))
classLabelVector= []
index= 0
for linein arrayOLines:
line= line.strip()
listFromLine= line.split('\t')
returnMatrix[index,:] = listFromLine[0:3]# 赋值方式很厉害!
classLabelVector.append(listFromLine[-1])
index+= 1
return returnMatrix,classLabelVector
数据中特征 "每月工资",取值范围太大,计算距离时,产生的影响过大.但我们认为 3 个特征的重要性是一样的.所以,有必要进行数据归一化处理.将数据归一化到 0~1 之间.
公式
newValue = (oldValue-min)/(max-min)
定义归一化函数 autoNorm;返回归一化的数据,每个特征的最小值以及范围(方便对新数据进行归一化处理).
其中,调用的函数
def autoNorm(dataSet):
minVals= dataSet.min(0)#a.min() : 全部的最小值;;a.min(axis=0): 每列中的最小值;a.min(axis=1): 每行中的最小值
maxVals= dataSet.max(0)
ranges= maxVals- minVals
m= dataSet.shape[0]# 行数
normDataSet= dataSet- tile(minVals,(m,1))#(m,n) 重复次数:行方向上重复 m 次,列方向上重复 1 次
normDataSet= normDataSet/tile(ranges,(m,1))
return normDataSet,ranges, minVals
dataSet.min(0)
dataSet:python numpy array 类型
array.min():求数组中的最小值
array.min(axis=0): 对数组中的每列求最小值
array.min(axis=1):对数组中的每行求最小值
numpy.tile(A, reps):
Construct an array by repeating A the number of times given by reps. 通过重复 A ,reps 次构建一个新的数组.
tile(minVals, (m, 1)): 重复 minVals 构造一个 m*1 的 copy
2. 分类算法 KNN
伪代码:
对未知类别属性的数据集中的每个点依次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增次序排序;
(3)选取与当前点距离最近的 k 个点;
(4)确定前 k 个点所在类别的出现频率;
(5)返回前 k 个点出现频率最高的类别作为当前点的预测分类.
其实是计算两个数据的相似性:有距离相似性度量和角度相似性度量【 knn 算法介绍 】.
这里采用距离相似性度量,欧式距离.
欧式距离计算公式
分类器算法实现:
其中,调用函数:
def classify0(inX, dataSet, labels, k):
dataSetSize= dataSet.shape[0]
diffMat= tile(inX,(dataSetSize,1)) - dataSet
sqDiffMat= diffMat** 2
sqDiffMat= sqDiffMat.sum(axis=1)# 按列求和
distances= sqDiffMat** 0.5
sortedDistIndicies= distances.argsort()#argsort 函数返回的是数组值从小到大的索引值
classCount= {}
for iin range(k):
voteLabel= labels[sortedDistIndicies[i]]
classCount[voteLabel] = classCount.get(voteLabel,0) + 1# 在字典 classCount 中通过 键 查找相应的值,如果字典中没有键,值为 0;有获取其值;最后加 1
sortedClassCount= sorted(classCount.items(),key=lambda a:a[1],reverse=True)# 根据出现次数排序,降序排序
return sortedClassCount[0][0]# 返回概率最大(出现次数最多的键,即类别)
numpy.argsort:
Returns the indices that would sort an array. 返回数组排序后的下标(默认升序排序).
eg:[10, 1, 51]
调用函数,返回的是:[1, 0, 2] ;1 是数据 1 的下标.
3. 测试算法
数据指标:误分率.
计算方法: 错误分类的记录数 / 测试数据的总数;
运行结果:
def datingClassTest():
"""
使用测试数据测试分类器效果
:return: 误分率 """
hoRatio= 0.10# 测试数据所占的比例 --- 将数据集按照 1:9 的比例划分,1 是测试集;9 是训练集
datingDataMat,datingLabels= file2Matrix('datingTestSet2.txt')
normMat,ranges,minVals= autoNorm(datingDataMat)
m= normMat.shape[0]# 数据集总数
numTestVecs= int(m*hoRatio)# 测试集数目
errorCount= 0
for i in range(numTestVecs):
classifierResult= classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print ("the classifier came back with: %s,the real answer is: %s" % (classifierResult, datingLabels[i]))
if (classifierResult!= datingLabels[i]):
errorCount+= 1
print ("the total error rate is: %f" %(errorCount/float(numTestVecs)))
测试算法运行结果
错误率:5%
4. 使用算法
重头戏:使用 knn 分类算法,方便小红约会哦!
percentTats= float(raw_input(\
def classifyPerson1():
resultList= ["不喜欢","魅力一般","极具魅力(韩国欧巴)"]
应用:
"花费在游戏,视频上的时间百分比?"))#raw_input: 读取控制台输入数据,赋值给变量,等效于 C++ 里的 cin>>a;
ffMiles= float(raw_input(" 每月工资有多少?"))
iceCream= float(raw_input(" 每年消耗的冰淇淋有多少升?"))
datingDataMat,datingLabels= file2Matrix("datingTestSet2.txt")
normMat,ranges,minVals= autoNorm(datingDataMat)
inArr= array([ffMiles,percentTats,iceCream])
classifierResult= classify0((inArr-minVals)/ranges,normMat,datingLabels,k=3)# 对输入数据进行归一化,然后再分类
print ("你将约会的人很可能是: %s" % resultList[int(classifierResult)-1])
小红将约会韩国欧巴(安排在周末)
小红遇到不喜欢的类型(pass)
5. 小结
A. 矩阵运算 ---- 能加快运算速度;
B.knn 算法分类数据简单有效,不用进行训练,是基于实例的学习,使用的数据必须接近实际数据的训练样本数据;必须保存所有数据,如果数据集过大,需要耗费巨大的存储空间;必须对数据中的所有样例点进行计算距离值,非常耗时(即使使用矩阵进行运算).
C.人生苦短,我用 Python!
来源: http://www.jianshu.com/p/0f9194850e85