1.k邻近算法直译为K个最近的邻居,是一种聚类算法。采用测量不同特征值之间的距离方法进行分类。基于大量数据的基础上,做出相应的预测,一般运用于手写数字识别,约会网站的大量数据匹配等等。
2.优点:精度高,对异常值不敏感,无数据输入假定.
3.缺点:计算复杂度高,空间复杂度高。
4.适用数据范围是:数值型和标称型。
以《机器学习实战》第二章导言为例我们需要鉴别某个电影的类别,我们通过比对发现他和我们列举的中5个电影相似,我们发现这5个镜头其中4个是打斗,1个是接吻,所以判定这部电影是武打片。这就是一个5NN算法。
总结出他的流程:
输入:数据x 已知类别的样本z
输出:x的类别y
1.计算数据x与z中每个样本的距离d
2.利用距离d获取与x距离前K小的索引index
3.利用index从样本z中选取出k个样本
导入两个模块,一个是科学计算包NumPy,还一个是运算符模块。定义createDataSet函数,使用该函数创建数据集和标签。
这里有4组数据,每组数据有两个我们已知的属性或特征值,向量labels包含了每个数据点的标签信息,labels包含的元素个数等于group矩阵行数。
from numpy import * #导入科学计算包Numpy
import operator #导入运算符模块
def createDataSet():
group=array([[3,104],[2,100],[101,10],[99,5]]) #导入四部电影[打斗镜头次数,接吻镜头]
labels=['A','A','B','B'] #labels分类标签,A为爱情片,B为接吻镜头
return group,labels
伪代码:对未知类别属性的数据集中的每个点依次执行以下操作
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增次序排序;
(3)选取与当前点距离最小的k个点;
(4)确定前k个点所在类别的出现频率;
(5)返回前k个点出现频率最高的类别作为当前点的预测分类。
def classify0(intX,dataSet,labels,k):
dataSetSize=dataSet.shape[0]
diffMat=tile(intX,(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.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
classify0 ()函数有4个输入参数:用于分类的输入向量是inX,dataSet输入的训练样本集,labels标签向量,k用于选择最近邻居的数目。其中标签向量的元素数目和矩阵dataSet的行数相同。程序所使用的欧氏距离公式,计算两个向量点xA和xB之间的距离:
计算完所有点之间的距离后,可以对数据按照从小到大的次序排序。然后,确定前k个距离最小元素所在的主要分类,输入k总是正整数;最后,将classCount字典分解为元组列表,然后使用程序第二行导入运算符模块的itemgetter方法,按照第二个元素的次序对元组进行排序。此处的排序是逆序,即按照从最大到最小次序排序,最后返回发生频率最高的元素标签
group,labels = createDataSet()
print(classify0([18,90],group,labels,3))
预测结果为A:爱情片。
A
若是训练数据集过大,每次都需要计算数据的距离值,实际耗时会过大,不仅时间开销大,存储空间的消耗也巨大。
构造一个能识别数字0到9的基于kNN分类器的手写数字识别系统。
需要识别的数字已经使用图形处理软件,处理成具有相同的色彩和大小:宽高是32像素✖32像素的黑白图像。
(1) 使用K-NN算法识别数字0-9,实现最基本的KNN算法,使用trainingDigits文件夹下的数据,对testDigits中的数据进行预测。
(2)改变K的值,并观察对正确率的影响。
def img2vector(filename):
return_vector = zeros((1, 1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
return_vector[0, 32 * i + j] = int(lineStr[j])
return return_vector
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('D:/study/机器学习/py code/kNN/trainingDigits')
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0]
#9
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector('D:/study/机器学习/py code/kNN/trainingDigits/%s' % fileNameStr)
#测试集
testFileList = listdir('D:/study/机器学习/py code/kNN/testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
#1*1024的列表
vectorUnderTest = img2vector('D:/study/机器学习/py code/kNN/testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)
print("预测值: ",classifierResult)
print("真实值: ",classNumStr)
if(classifierResult!=classNumStr):
errorCount += 1.0
print("总共错误的数量为: ",errorCount)
print("错误率为: ",(errorCount)/float(mTest))
预测结果为:
...
预测值: 9
真实值: 9
预测值: 9
真实值: 9
总共错误的数量为: 10.0
错误率为: 0.010570824524312896
1.在本次实验中,我完成了理解了KNN算法,是分类数据最简单有效的算法,但是如果训练数据集很大,存储空间就必须够大,并且算法的执行效率不高。正如手写数字识别系统这个案例,维度高、样本多,计算过程就十分繁琐,不太适合。
2.我了解了传统机器学习算法,为后序深度学习打牢基础。