您的位置:首页 > 其它

机器学习-kNN算法改进约会效果

2014-05-22 17:11 453 查看
最近在学习《机器学习实战》
kNN算法是从训练集中找到和新数据最接近的k条记录(欧氏距离),然后根据他们的主要分类来决定新数据的类别。该算法涉及3个主要因素:训练集、距离或相似的衡量、k的大小。

kNN算法可以解决如下问题
样本如下:

     span group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
     labels = ['A','A','B','B']


然后要判断[1.1,1.2],[0.1,0.2]属于哪一类
首先导入数据
  def createDataSet(): #训练样本及标签
      group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
      labels = ['A','A','B','B']
      return group, labels


然后我们使用kNN算法
对待测样本点执行以下操作
1、计算待测点与样本点的欧氏距离;
2、按距离递增次序排列;
3、选择前k个点,计算其对应的标签,对标签次数按降序排列;
4、选择出现次数最多的标签作为kNN算法的预测结果
代码如下:

mat.sum(axis=0) 计算行和

mat.sum(axis=1) 计算列和

argsort() 返回排序后的下标

<pre name="code" class="python">def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]#返回dataSet的行数(训练样本数)
'''
tile(a,(b,c)):将a的内容在行上重复b次,列上重复c次
下面这一行代码的结果是将待分类数据集扩展到与已有数据集同样的规模,然后再与已有数据集作差
'''
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2#对其差值就平方
sqDistances = sqDiffMat.sum(axis=1)#对每一行的值求和
distances = sqDistances**0.5#开方,计算欧氏距离
sortedDistIndicies = distances.argsort() #对距离排序
classCount={}    #建立空字典,类别字典,保存各类别的数目
for i in range(k):  #寻找k个最近邻
voteIlabel = labels[sortedDistIndicies[i]]#先找出开方结果索引表中第i个值对应的Label值
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1   # 存入当前label以及对应的类别值
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)#对类别字典进行逆排序,级别数目多的往前放

return sortedClassCount[0][0] #返回级别字典中的第一个值,也就是最有可能的Label值



然后执行以下命令
  import kNN
  >>> group,labels=kNN.createDataSet()
  >>> kNN.classify0([1.1,1.2],group,labels,3)
  'A'
  >>> kNN.classify0([0.1,0.2],group,labels,3)
  'B'
  >>>


用kNN改进约会网站配对效果

首先要从文本文件中解析数据,文本文件中统计了以下3中特征:

1、每年获得的飞行常客里程数(不太明白什么意思)

2、玩视频游戏所消耗时间

3、每周消费的冰淇淋公升数

该程序如下:

def file2matrix(filename):
fr = open(filename)                         #打开文件
numberOfLines = len(fr.readlines())         #得到文件行数
returnMat = zeros((numberOfLines,3))        #创建一个numberOfLines行3列的纯0数组
classLabelVector = []                       #建立空的类标签
fr=open(filename)<span style="white-space:pre">			</span>#这个不清楚为什么还要打开一次,求大神
index = 0                                   #文本数据的行数从0行开始复制
for line in fr.readlines():
line = line.strip()                     #去掉回车字符
listFromLine = line.split('\t')         #用tab(\t)将整行数据分割成一个元素列表
returnMat[index,:] = listFromLine[0:3]  #复制数据
classLabelVector.append(int(listFromLine[-1]))  #最后一列存储到classLabelVector
index += 1
return returnMat,classLabelVector


如果去掉第二个

fr=open(filename)


语句,那么返回的全是空数组,这个我也不知道为什么,求解~~~

运行程序可以得到

>>> import kNN
>>> datingDataMat,datingLabels = kNN.file2matrix('datingTestSet.txt')
>>> import matplotlib
>>> import matplotlib.pyplot as plt
>>> fig=plt.figure()
>>> ax=fig.add_subplot(111)
>>> ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
<matplotlib.collections.PathCollection object at 0x034ED570>
>>> plt.show()


得到的效果图是这样的



归一化数据,以避免数据之间的相互影响,采用

newValue=(oldValue-min)/(max-min) 将任意取值范围的特征值转化到【0 1】之间

def autoNorm(dataSet):
minVals = dataSet.min(0)                        #(0)取每列的最小值,(1)取每行的最小值
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))             #生成和dataSet同大小的零矩阵
m = dataSet.shape[0]                            #获取dataSet的行数复制给m,
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges, (m,1))   #归一化
return normDataSet, ranges, minVals


机器学习的算法最重要的是要保证算发的正确率,这个例子用90%作为训练样本,10%作为测试,因为数据是随机分布的,索引选择前10%的数据用来测试

分类针对约会网站的代码如下

def datingClassTest():
hoRatio = 0.10      #%10作为测试样本
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #读取样本
normMat, ranges, minVals = autoNorm(datingDataMat)             #归一化
m = normMat.shape[0]            #读取的样本数
numTestVecs = int(m*hoRatio)    #测试样本数
errorCount = 0.0                #错误数0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
#用classify0进行分类,选取前%10作为测试样本,其他的作为训练样本,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        #错误数


综上,加上一下代码,用于实现网站约会的预测

def classifyPerson():
resultList = ['not at all','in small doses','in large doses']         #可能输出的结果
percentTats = float(raw_input("percentage of time spent playing video games?")) #输入看电影的时间
ffMiles = float(raw_input("frequent flier miles earned per year?"))   #坐飞机时间
iceCream = float(raw_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] #数据标签是1,2,3,因此要减1


参考资料:ht tp://www.2cto.com/kf/201405/299627.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: