k-近邻算法
本章内容
k-近邻分类算法
从文本文件中解析和导入数据
使用Matplotlib创建扩散图
归一化数值
K-近邻(k-Nearest Neighbor,KNN),是一种常用于分类
的算法,是有成熟理论支撑的、较为简单的经典机器学习算法之一。本文主要讲解如何在实际环境中应用k-近邻分类算法,同时涉及如何使用Python工具和相关机器学习术语,算法原理详见数据挖掘十大算法–K近邻算法。
Github代码获取
https://github.com/Ivan020121/Machine-Learning/tree/main/K-nearest%20neighbor%20algorithm
k-近邻算法概述
简单地说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。
k-近邻算法
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
它的工作原理是:存在一个样本数据集合
,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据
(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
k-近邻算法的一般流程
(1) 收集数据:可以使用任何方法
(2) 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3) 分析数据:可以使用任何方法。
(4) 训练算法:此步骤不适用于k-近邻算法。
(5) 测试算法:计算错误率。
(6) 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
准备:使用Python导入数据
首先,创建名为kNN.py
的Python模块。
from numpy import*
import operator
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
k-近邻算法:带有4个数据点的简单例子
在上面的代码中,我们导入了两个模块:一个是科学计算包NumPy,第二个是运算符模块,k-近邻算法执行排序操作时将使用这个模块提供的函数,后面我们将进一步介绍。
实施kNN分类算法
k-近邻算法的伪代码
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前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.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
classify0()函数有4个参数输入:用于分类的输入向量是inX,输入的训练样本集为dataSet,标签向量为labels,最后的参数k
表示用于选择最近邻居的数目
,其中标签向量的元素数目和矩阵dataSet的行数相同。
示例:使用k-近邻算法改进约会网站的配对效果
示例:在约会网站上使用k-近邻算法
(1) 收集数据:提供文本文件。
(2) 准备数据:使用Python解析文本文件。
(3) 分析数据:使用Matplotlib画二维扩散图。
(4) 训练算法:此步骤不适应与k-近邻算法
(5) 测试算法:使用海伦提供的部分数据作为测试样本。
(6) 使用算法:产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。
准备数据:从文本文件中解析式数据
数据文本文件:datingTestSet2.txt.样本主要包含以下3种数据:
每年获得的飞行常客里程数
玩视频游戏所消耗时间百分比
每周消费的冰淇淋公升数
在kNN.py中创建名为file2matrix
的函数,以此来处理输入格式问题。
def file2matrix(filename):
fr = open(filename)
numberOfLines = len(fr.readlines()) #get the number of lines in the file
returnMat = zeros((numberOfLines,3)) #prepare matrix to return
classLabelVector = [] #prepare labels return
fr = open(filename)
index = 0
for line in fr.readlines():
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
分析数据:使用Matplotlib创建散点图
下面就用Python工具来图形化展示
数据内容,以便辨识出一些数据模式
。
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()
约会数据散点图
准备数据:归一化数值
在量纲不一而对比标准统一的时候需要做归一化,数据归一化的目的是为了把不同来源的数据统一到一个参考系
下,这样比较起来才有意义。
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)) #element wise divide
return normDataSet, ranges, minVals
测试算法:作为完整程序验证分类器
为了测试分类器效果,在kNN.py文件中创建datingClassTest
。
def datingClassTest():
hoRatio = 0.50 #hold out 10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file
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("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)))
print(errorCount)
示例:手写识别系统
k-近邻分类器的手写识别系统。
示例:使用k-近邻分类器的手写识别系统
(1) 收集数据:提供文本文件。
(2) 编写img2vector(),将图像格式转换为向量格式。
(3) 分析数据:检查数据。
(4) 训练算法:此步骤不适用于k-近邻算法
(5) 预测分类并与实际分类对比。
(6) 使用算法:完成数字识别系统。
准备数据:将图像转换为测试向量
数据目录:trainingDigits testDigits
函数img2vector将图像格式化处理为一个1×1024
的向量,将上述代码输入到kNN.py文件中。
def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
测试算法:用k-近邻分类器的识别手写数字
自包含
函数handwritingClassTest()是测试分类器的代码,将其写入kNN.py文件中。
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits') #load the training set
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = listdir('testDigits') #iterate through the test set
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] #take off .txt
classNumStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr))
if (classifierResult != classNumStr): errorCount += 1.0
print("\nthe total number of errors is: %d" % errorCount)
print("\nthe total error rate is: %f" % (errorCount/float(mTest)))
小结
k-近邻算法是分类数据最简单最有效的算法,是基于实例
的学习,使用算法时我们必须有接近实际数据
的训练样本数据。k-近邻算法必须保存全部数据集,如果训练数据集的很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。
🤯本文作者:Ivan
🔗本文链接:https://ivan020121.github.io/2022/03/31/kNN/
🔁版权声明:本站所有文章除特别声明外,均采用©BY-NC-SA许可协议。转载请注明出处!