作为一个初学者,本博客为在学习<<机器学习实战>>一书的一些笔记和个人的一些理解.
1.k近邻思想
中国有古话”物理类聚,人以群分”,k近邻思想貌似也是这个意思.例如我想判断一个人是好人还是坏人,但是我对这个人根本不了解,那么我如何去判断呢?当然,如果不给我任何其它条件那么我只能靠”颜值”去判断了…,所以这里有个条件——-我虽然不认这个人,但我认识他所有的朋友并且知道他的每一个朋友是好人还是坏人.例如如他的10个朋友其中有8个朋友是坏人,2个是好人,那么我就可以判断他很可能是个坏人,反之亦然.
那么在数据集中又是如何体现的呢?假设给我们一堆已知类别的二维数据
{(x0,y0),(x1,y1)⋯,(xn,yn)}
并且已知数据一共分为三类
z1,z2,z3
(实际情况可能是三维四维等更复杂的情况,但是原理应该都是一样的),然后给我一个
(x,y)
让我去确定这个未知的
(x,y)
的类别.那么我应该如何应用k近邻算法呢?
* 步骤1:计算
(x,y)
与所有已知数据
(xi,yi)
的欧式距离
*步骤2:选取距离 (x,y) 最近的k个点
*步骤3:统计k个点中三个类别标签的个数
*步骤4:选取标签个数最多的类别作为 (x,y) 的类别
这样一来就可以判定 (x,y) 的类别了.
2.k近邻算法的代码实现
使用python实现k近邻算法,代码和数据集除了注释和个别地方修改,其它均来自<<机器学习实战>>一书,完整python代码和数据集可以在我的github上找到:代码链接
2.1创建数据
'''
输入:无
输出:数据和数据对应的标签()类别
功能:创建一个数据集
'''
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
2.2k近邻算法
'''
输入:待分类数据,已知数据集,数据集对应的标签,k
输出:待分类数据的类别
功能:对输入的未知数据根据已知数据集进行分类
'''
def classify0(inX,dataSet,labels,k):#inX:待分类数据,dataSet:数据集,labels:数据集对应标签,k指定距离inX最近数据点的个数
dataSetSize=dataSet.shape[0] #获取数据个数
diffMat=tile(inX,(dataSetSize,1))-dataSet #x-x1,y-y1
sqDiffMat=diffMat**2 #(x-x1)^2
sqDistances=sqDiffMat.sum(axis=1) #
distances=sqDistances**0.5 #距离D
sorteDistIndicies=distances.argsort() #对距离从小到大排序
classCount={}
for i in range(k): #统计前k个距离个各个类标签出现的次数
voteIlabel=labels[sorteDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]#返回出现次数最多的类别标签
2.3对数据归一化
为什么要数据归一化呢?例如我们训练数据
(0.1,100)
其中的第一个特征与第二个特征差别的别大,那么在计算距离
其中的第二个特征对数据的结果影响十分大,而第一个特征几乎忽略不计了,因此为了避免特征数值范围相差过大对结果的影响我们将所有数据归一化处理
其中 xnew 为归一化后的特征向量, xmin,xmax 为原特征向量每一特征向量的最小值与最大值.这样对每个特征向量进行处理,就可以把所有数据规划的 (0,1) 之间,从而避免了,不同特征取值范围差别过大而影响分类结果.
'''
输入:数据集
输出:归一化后的数据集
功能:正则化数据
公式:(x-xmin)/(xmax-xmin)
'''
def autoNorm(dataSet):
minVals = dataSet.min(0) #min()参数0,找出每一列的最小值
maxVals = dataSet.max(0)
ranges = maxVals-minVals
normDataSet = zeros(shape(dataSet))
m=dataSet.shape[0]
normDataSet=dataSet-tile(minVals,(m,1))#tile()把,minVlas,复制m行,1列
normDataSet =normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
2.4综合测试
数据集在我的github上
'''
输入:无
输出:分类正确率
功能:综合测试kNN分类器正确率
'''
def datingClassTest():
hoRatio=0.10 #训练数据集:测试数据集=1:9
datingDataMat,datingLabels=file2matrix('datingTestSet.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 calssifier came back with:%d,the real answer is:%d" % (classifierResult,datingLabels[i]))
if (classifierResult != datingLabels[i]):
errorCount +=1
print("the total error rate is: %f" %(errorCount/float(numTestVecs)))
在python3命令行模式输入
import kNN
kNN.datingClassTest()
得到如下输出结果:可见其错误率仅为
5%
!