博客内容源于《统计机器学习》一书的阅读笔记。Python的源码实现源于《机器学习实战》部分内容。
1. K近临算法
【算法描述】给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最近临的K个实例,这个k个实例的多数属于某个类,就把该输入实例分为这个类。
【数学描述】
输入:训练数据集
其中, xi∈X⊆Rn 为实例的特征向量, yi∈Y={c1,c2,...,cK} 为实例类别, i=1,2,...,N ;实例特征向量 x ;
输出:实例
【算法求解过程】
1. 根据给定的距离度量,在训练集
2. 在
Nk(x)
中根据分类决策规则(比如多数表决)决定
x
的类别
上式中,函数 I 为指示函数,当
2. K近临模型
K近临模型由三个参数决定:距离度量,k值和分类决策规则。
2.1 距离度量
设特征空间
X
是
n
维实数向量空间
2.1.1 欧氏距离(Euclidean Distance)
欧氏距离是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式。上述公式中
p=2
时,称为欧式距离:
2.1.2 曼哈顿距离(Manhattan Distance)
p=1
时,称为曼哈顿距离:
2.1.3 夹角余弦(Cosine)
几何中夹角余弦可用来衡量两个向量方向的差异,机器学习常常中用这一概念来衡量样本向量之间的差异。
2.2 K值选取
K值的选取会对k近临算法的结果产生很大的影响。
- K值很小时,预测结果会对噪声特别敏感。假设临近的实例点恰好是噪声,预测的结果就会出错。
- K值很大,与输入实例距离较远的实例点也会起作用,导致预测的结果出错。
2.3 分类决策
k近临中的分类决策规则往往使用多数表决,即由输入实例的k个邻近的训练实例中的多数类决定输入实例的类。
【多数表决】
如果分类的损失函数为0-1损失函数,分类函数为
那么误分的概率是
对于给定的实例 x∈X , 其最近邻的k个训练实例点构成集合 Nk(x) 。如果涵盖 Nk(x) 的区域的类别是 cj , 那么误分率是:
要使误分类率最小(经验风险最小),就要使 ∑xi∈Nk(x)I(yi=cj) 最大,所以多数表决规则等价于经验风险最小化。
3. K近临举例
数据来自于《机器学习实战》一书中,数据下载链接:
https://github.com/bzhou830/ML-python/blob/master/ch1-KNN/datingTestSet2.txt
1.从文件中导入元数据
def file2matrix(filename):
fr = open(filename) #打开文件
arrayOfLines = fr.readlines() #读取文件行数
numberOfLines = len(arrayOfLines) #文件行数
returnMat=zeros((numberOfLines,3)) #矩阵
classLabelVector = [] #标签
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
2.使用matplotlib绘制数据集合图像
def PrintFigure(datingDataMat,datingLabels):
fig = plt.figure()
ax=fig.add_subplot(111, projection='3d')
#绘制三维图
num = len(datingDataMat)
for i in range(num):
if datingLabels[i] == 1:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='b', marker='x')
elif datingLabels[i] == 2:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='r', marker='o')
elif datingLabels[i] == 3:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], c='g',marker='*')
elif datingLabels[i] == 0:
ax.scatter(datingDataMat[i][0],datingDataMat[i][1],datingDataMat[i][2], marker='1')
plt.show()
可以直观的看到元数据有三类。
3.完整程序
'''
inx 输入向量
dataSet 训练数据集
labels 训练数据集标签
k 最临近数目
'''
def classify0(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 #向量的长度
sortedDistIndicies = distances.argsort() #数组从小到大的索引值
classCount={} #类统计
for i in range(k): #最临近数目
voteIlabel = labels[sortedDistIndicies[i]] #最临近数的标签
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #统计标签个数
sortedClassCount=sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)#排序
return sortedClassCount[0][0] #返回数量最多的标签
def file2matrix(filename):
fr = open(filename) #打开文件
arrayOfLines = fr.readlines() #读取文件行数
numberOfLines = len(arrayOfLines) #文件行数
returnMat=zeros((numberOfLines,3)) #矩阵
classLabelVector = [] #标签
index = 0
for line in arrayOfLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
'''
dataSet 传入矩阵数据集
normDataSet 返回归一化后数据集
ranges
minVals
'''
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.20 #测试数据集所占比例
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)
print "Rt is %d, Real is %d" % (classifierResult,datingLabels[i])
if(classifierResult != datingLabels[i]):
errorcount += 1.0
print " %f " % (errorcount/float(numTestVecs))
程序文件可以可以到github上下载:https://github.com/bzhou830/ML-python/