作为一个菜鸟,在刚开始做这个的时候很多函数都不懂,所以打算把它写下来,做一个详细的说明,可能有很多地方用词不准确,欢迎指证,感激不尽。
首先是构造分类器函数:
from numpy import *
import operator
def classfuction(inx,dataset,labels,k): #输入需要分类的数据inx,数据集dataset,数据集对应标签为labels,最临近数目k
datasetsize=dataset.shape[0] # shape[1] 为第二维的长度,shape[0] 为第一维的长度。就是列的长度。
diffmat=tile(inx,(datasetsize,1))-dataset #重复A,B次,这里的B可以时int类型也可以是元祖类型。计算inx和每个样本的距离。
sqdiffmat=diffmat**2
sqdistances=sqdiffmat.sum(axis=1) #加入axis=1以后就是将一个矩阵的每一行向量相加
distances=sqdistances**0.5 #开根号,计算欧几里得距离即a与b之间的距离等于根号下对应各个特征的差的平方。
sorteddistindicies=distances.argsort() #返回从小到大的索引
classcount={} #创建一个字典
for i in range(k):
voteilabel=labels[sorteddistindicies[i]]
classcount[voteilabel]=classcount.get(voteilabel,0)+1 #Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值。
sortdeclasscount=sorted(classcount.items(),key=operator.itemgetter(1),reverse=True) #排序sorted(iterable, key=None, reverse=False)
#iterable -- 可迭代对象。key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
return sortdeclasscount[0][0] #是降序排列,所以返回的是数目最多的类别的标签
group=np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) #构造数据集。。。
labels=['A','A','B','B']
classfuction([0,0],group,labels,3)
然后是转换数据格式
import numpy as np
def file2matrix(filename):
fr=open(filename) #首先打开文件
arrayolines=fr.readlines() #读取文件所以行并返回列表
numberoflines=len(arrayolines)#计算出一共有多少行数据
returnmax=np.zeros(( numberoflines,3))#建立出一个相同大小的零值矩阵
classlabelvector=[]#建立一个列表
index=0#初始索引
for line in arrayolines :
line=line.strip()#用于移除字符串头尾指定的字符(默认为空格)。
listfromline=line.split('\t')#通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则仅分隔 num 个子字符串,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等
returnmax[index,:]=listfromline[0:3]#将得到的行数据赋给我们建立好的零值矩阵
classlabelvector.append(int(listfromline[-1]))#观察原数据我们可知,标签为最后一列,所以将最后一位数据赋给标签列表
index+=1#索引加一,给下一行继续赋值
return returnmax,classlabelvector#返回数据矩阵以及标签列表
datingdatamat,datinglabels=file2matrix("datingTestSet2.txt")
接下来是数据可视化,我个人认为这在机器学习中比较重要,它可以展现出哪些特征用于分类会有更好的效果。
import matplotlib
import matplotlib.pyplot as plt
zhfont = matplotlib.font_manager.FontProperties(fname='C:\Windows\Fonts\STXINWEI.ttf')
fig=plt.figure()#得到fig对象
ax=fig.add_subplot(111)#得到axis对象,图像在一行一列的第一位
ax.scatter(datingdatamat[:,1],datingdatamat[:,2],17.0*np.array(datinglabels),17.0*np.array(datinglabels))#绘制散点图,后两位设置尺寸和颜色
plt.xlabel("玩视频游戏的时间百分比",fontproperties=zhfont) #设置标签以及中文字体
plt.ylabel("每周冰淇淋消耗公升数",fontproperties=zhfont) #设置标签以及中文字体
plt.show()
对数据进行归一化处理。避免出现因为数据的取值范围的原因影响预测结果。
#归一化处理
from numpy import *
def autonorm(dataset):
minvals=dataset.min(0) #每列最小,索引为0.如果为1,代表每行的最小值,若无参数,为所有中的最小值
maxvals=dataset.max(0)#同理
ranges=maxvals-minvals#列表相减
normdataset=np.zeros(shape(dataset))#建立一个同样规格的零值矩阵
m=dataset.shape[0]#读取矩阵的长度,shape[0]就是读取矩阵第一维度的长度。
normdataset=dataset-tile(minvals,(m,1))#重复A B次,相当于每个数据都减去了最小值。
normdataset=normdataset/tile(ranges,(m,1))#上一步减去最小值之后,现在再除以最大值减去最小值
return normdataset,ranges,minvals
normmat,ranges,minvals=autonorm(datingdatamat)
进行分类测试,用之前构建的分类器函数以及前面提到的各种数据处理。最后输出错误率以及预测结果和实际结果。
def datingclasstest():
horatio=0.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=classfuction(normmat[i,:],normmat[numtestvecs:m,:],datinglabels[numtestvecs:m],3)#将后0.9的数据用于训练集
print(classifierresult,datinglabels[i])
if classifierresult!=datinglabels[i]:
errorcount+=1.0
print(errorcount/float(numtestvecs))#计算错误率
datingclasstest()
最后是建立一个可以用来预测新数据的分类函数。
def classifyperson():
resultlist=['不喜欢','有一点点喜欢','很喜欢']#输出有几类结果
percenttats=float(input("一周玩多久的电子游戏"))#输入三个特征
ffmiles=float(input("每年飞多远"))
icecream=float(input("一周吃多少冰淇淋"))
datingdatamat,datinglabels=file2matrix("datingTestSet2.txt")
normmat,ranges,minvals=autonorm(datingdatamat)
inarr=array([ffmiles,percenttats,icecream])
classifierresult=classfuction((inarr-minvals)/ranges,normmat,datinglabels,3)#输入归一化数据
print(resultlist[classifierresult-1])#标签是1,2,3.所以需要减一才能作为索引。
classifyperson()