作者:蓝星星空 | 来源:互联网 | 2023-09-24 19:55
参考自:《MachineLearningInAction》第二章#################################################################
参考自:《Machine Learning In Action》第二章
######################################################################
程序流程:
1.收集数据:提供文本文件
2.准备数据:使用Python解析文本文件
3.分析数据:使用Matplotlib画二维扩散图
4.测试算法:使用提供的部分数据作为测试样本。
测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误
5.使用算法:产生简单的命令行程序,然后可以输入一些特征数据以判断结果
###########################################################
本样本共有三种特征:
每年获得的飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
数据存放在文本文件datingTestSet2.txt文件中,每个样本数据占据一行,总共有1000行
#!/usr/local/env python
#-*- coding: utf-8 -*-
from numpy import * #导入科学计算包numpy模块
import operator #导入运算符模块
#k-近邻分类算法
def classify0(inX, dataSet, labels, k): #4个输入参数分别为:用于分类的输入向量inX,输入的训练样本集dataSet,标签向量labels,选择最近邻居的数目k
#计算距离
dataSetSize=dataSet.shape[0] #获取数据集的宽
diffMat=tile(inX, (dataSetSize, 1))-dataSet #使用欧式距离度量,故将输入向量和数据集中各向量相减
sqDiffMat=diffMat**2 #平方
sqDistances=sqDiffMat.sum(axis=1) #计算输入向量和数据集中各向量之间的差的平方和
distances=sqDistances**0.5 #计算欧式距离
#选择距离最小的k个点 计算所属类别的出现频率
sortedDistIndicies=distances.argsort() #取得输入向量和数据集中各向量欧式距离的从小到大排序的下标值
classCount={} #定义一个空字典
for i in range(k): #取计算欧氏距离排序后最小的前k个值
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
#排序 选择前k个点中出现最多的那一个类
sortedClassCount=sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
#将文本记录转换为Numpy的array
def file2matrix(filename): #输入为文件名字符串
fr=open(filename) #打开文件
arrayOLines=fr.readlines() #取得该文件的每行数据的列表
numberOfLines=len(arrayOLines) #计算该文件共有多少行(即共有多少个样本)
returnMat=zeros((numberOfLines, 3)) #创建返回的Numpy矩阵
classLabelVector=[]
index=0
for line in arrayOLines: #解析文件数据到列表
line=line.strip() #去掉首尾空白符
listFromLine=line.split('\t') #利用空格符分离字符串
returnMat[index, :]=listFromLine[0:3] #将每行样本数据的前3个数据输入返回样本矩阵中
classLabelVector.append(int(listFromLine[-1])) #将每行样本数据的最后一个数据加入类标签向量中
index+=1
return returnMat, classLabelVector #返回训练样本矩阵和类标签向量
#归一化特征值
def autoNorm(dataSet): #输入为数据集数据
minVals=dataSet.min(0) #获得数据集中每列的最小值
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 #返回归一化矩阵,取值范围以及最小值
#测试程序
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 #初始化错误率
for i in range(numTestVecs): #循环,计算测试样本集错误数量
classifierResult=classify0(normMat[i,:], normMat[numTestVecs:m,:], datingLabels[numTestVecs:m], 3) #k-近邻算法
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)) #计算错误率,并输出
#自定义分类器:输入信息并得出结果
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 filer miles earned per year?"))
iceCream=float(raw_input("liters of icecream 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]
########################################################3
代码解析
在将上述特征数据输入到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格式。
使用file2matrix函数,输入为文件名字符串,输出为训练样本矩阵和类标签向量
在处理不同取值范围的特征值时,通常将其数值归一化,如将取值范围处理为0到1或者-1到1之间。
下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:
newValues=(oldValues-min)/(max-min)
其中min和max分别是数据集中的最小特征值和最大特征值
使用函数autoNorm(),讲数字特征值转化为0到1区间