目录
一、k-近邻算法概述
1.概念
给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,也就是所说的k个邻居,这k个实例的多数属于某个类,就把该输入实例分类到这个类中(类似于现实生活中少数服从多数的思想)。k近邻算法是一种用于分类和回归的统计方法,可以说是最简单的分类算法之一,同时,也是最常用的分类算法之一。
2.工作原理
如上图所示,有两类不同的样本数据,分别用蓝色的小正方形和红色的小三角形表示,而图正中间的绿色的圆表示为待分类的数据。相当于来了一个新的数据点,想求得它的类别是什么?那么,我们可以根据k近邻算法来给绿圆进行分类。
*如果k=3,绿圆最邻近的3个点为2个红色小三角和1个蓝色小正方形,少数服从多数,判定绿圆这个待分类点属于红色的三角形一类。
*如果k=5,绿圆最邻近的5个点为2个红色小三角和3个蓝色小正方形,还是少数服从多数,判定绿圆这个待分类点属于蓝色的正方形一类。
懂了,也知道怎么给新来的点如何进行归类,只要找到离它最近的k个实例,哪个类别最多即可。
3.k-近邻算法的一般流程
(1)收集数据:可以使用任何方法。
(2)准备数据:距离计算所需要的数值,最好是结构化的数据格式。
(3)分析数据:可以使用任何方法。
(4)训练算法:此步骤不适用于k-近邻算法。
(5)测试算法:计算错误率。
(6)使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
4.距离度量
特征空间中两个实例点之间的距离是二者相似程度的反应,所以k近邻算法中一个重要的问题是计算样本之间的距离,以确定训练样本中哪些样本与测试样本更加接近。
距离
当p=2,为欧氏距离(Euclidean Distance)
当p=1,为曼哈顿距离(Manhattan Distance)
当p=∞,为各个坐标距离的最大值
(1)欧氏距离(Euclidean Distance)
欧氏距离是最常见的距离度量,衡量的是多维空间中两个样本点之间的绝对距离。假设多维空间的维度为N,,
,……,
和
,
,……,
是两个样本点,则
和
之间的欧氏距离计算公式为
可见,欧氏距离由两个样本之间每一维度之差的平方和计算而来。当维度之间的取值范围差别太大时,欧氏距离容易被那些取值范围大的变量所主导,从而大大降低模型的效果。因此,如果采用欧氏距离作为相似度度量,最好提前对数据进行标准化转换。
(2)曼哈顿距离(Manhattan Distance)
曼哈顿距离,也被称为出租车几何。曼哈顿距离计算公式为:
曼哈顿距离等于两个样本之间每一维度之差的绝对值之和。曼哈顿距离的含义可以对应到规划为方框建筑的城市(如曼哈顿),两个地点的出租车最短行驶距离。在使用曼哈顿距离时,也需要考虑变量之间取值范围不同对结果的影响。
5.kNN算法的优势
(1)精度高
(2)对异常值不敏感
(3)无数据输入假定
二、基于k-近邻算法的实例
1.准备数据:从文本文件中解析数据
def fileMatrix(filename):
file = open(filename)
arrayOLines = file.readlines()
numberOfLines = len(arrayOLines)
returnMat = zeros((numberOfLines, 3))
classLabelVector = []
index = 0
for line in arrayOLines:
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 showdatas(datingDatMat, datingLabels, numScatter, xylabel):
fig = plt.figure()
font = {'family': 'MicroSoft YaHei'}
matplotlib.rc("font", **font)
ax = fig.add_subplot(111)
ax.scatter(datingDatMat[:, numScatter[0]], datingDatMat[:, numScatter[1]], 15.0 * array(datingLabels), 15.0 * array(datingLabels))
ax.set_xlabel(xylabel[1])
ax.set_ylabel(xylabel[2])
plt.title(xylabel[0])
plt.show()
datingDatMat, datingLabels = fileMatrix('datingTestSet.txt')
numScatter = array([[0, 1], [0, 2], [1, 2]])
xylabel = array([['每年获得飞行常客里程数与玩视频游戏所消耗占比', '每年获得的飞行常客里程数', '玩视频游戏所消耗时间占'],
['每年获得飞行常客里程数与每周消费的冰激淋公升数', '每年获得的飞行常客里程数', '每周消费的冰激淋公升数'],
['玩视频游戏所消耗时间占比与每周消费的冰激淋公升数', '玩视频游戏所消耗时间占比','每周消费的冰激淋公升数']])
showdatas(datingDatMat, datingLabels, numScatter[0], xylabel[0])
showdatas(datingDatMat, datingLabels, numScatter[1], xylabel[1])
showdatas(datingDatMat, datingLabels, numScatter[2], xylabel[2])
3.准备数据:数据归一化
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
datingDatMat, datingLabels = fileMatrix('datingTestSet.txt')
normData, ranges, minVals = autoNorm(datingDatMat)
print('normData')
print(normData)
print('ranges')
print(ranges)
print('minVals')
print(minVals)
4.测试算法:作为完整程序验证分类器
def datingClassTest():
hoRatio = 0.1 #10%的测试数据
datingDatMat, datingLabels = fileMatrix('datingTestSet.txt') #从文件读数据
normMat, ranges, minVals = autoNorm(datingDatMat) #数据的归一化
m = normMat.shape[0]
numTestVecs = int(m*hoRatio) #测试数据数量
errorCount = 0.0 #错误数量统计
for i in range(numTestVecs):
classifierResult = classify(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
print("分类器返回的结果是:%d,真实结果是:%d"%(classifierResult, datingLabels[i]))
if(classifierResult != datingLabels[i]):
errorCount += 1.0
print('分类器处理约会数据集的错误率是:%f'%(errorCount/float(numTestVecs)))
5.使用算法:构建完整可用系统
def classifyPerson():
#输出结果
resultList = ['讨厌','有些喜欢','非常喜欢']
#三维特征用户输入
ffMiles = float(input("每年获得的飞行常客里程数:"))
precentTats = float(input("玩视频游戏所耗时间百分比:"))
iceCream = float(input("每周消费的冰激淋公升数:"))
#打开的文件名
filename = "datingTestSet.txt"
#打开并处理数据
datingDataMat, datingLabels = file2matrix(filename)
#训练集归一化
normMat, ranges, minVals = autoNorm(datingDataMat)
#生成NumPy数组,测试集
#inArr = np.array([precentTats, ffMiles, iceCream])
inArr = np.array([ffMiles, precentTats, iceCream])
#测试集归一化
norminArr = (inArr - minVals) / ranges
#返回分类结果
classifierResult = classify0(norminArr, normMat, datingLabels, 3)
#打印结果
print("你可能%s这个人" % (resultList[classifierResult-1]))
三、总结
我们提出了k近邻算法,算法的核心思想是,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中。即来了一个新的输入实例,我们算出该实例与每一个训练点的距离,然后找到前k个,这k个哪个类别数最多,我们就判断新的输入实例就是哪类。
得:k值太小欠拟合,k值过大过拟合。
至此,本次学习结束。