K-近邻算法详细介绍
刚开始学习机器学习,在做K-近邻算法时,看很多关于这方面的资料,然后总结了一下。有不对的地方,希望大家批评指正。
概念定义
K-近邻算法:
第一句:给定一个带标签的样本数据集合(称为:训练集)
第二句:当输入没有标签的新数据(新数据:测试集中的数据)后
第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较
第四句:选择训练集中前K个最相似(最近邻)的数据,提取前K个最相似的数据的分类标签,(说明:通常K是不大于20的整数)。
第五句:选择这K个最相似数据中出现次数最多的类别标签,作为新数据的类别标签
1.1、抽象举例解释
例子1:图形判断
解释:第一句:给定一个带标签的样本数据集合(称为:训练集)
如下图所示:红色三角形和蓝色正方形组成的集合称为训练集,标签只有三角形,正方形。
解释:第二句:当输入没有标签的新数据(新数据:测试集中的数据)后。
图中,中间的绿色图形表示的是没有标签的新数据
第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较
这里采用欧式距离进行比较,即:比较两点间的距离的大小。距离越大,相似性就越小;距离越小,相似性就越大。(遗留问题1:相似性比较方法有哪些?)
第四句:选择训练集中前K个最相似(距离最小)的数据,提取训前K个最相似的数据的分类标签,(遗留问题2:k的值设定多少才合适)
第五句:选择这K个最相似数据中出现次数最多的类别标签(多数表决规则),作为新数据的类别标签(遗留问题3:多数表决规则怎样通过数学来解释)
1.2、现实举例解释
例子:电影类型评估
解释1:第一句:给定一个带标签的样本数据集合(称为:训练集)
电影名称 |
打斗镜头 |
接吻镜头 |
电影类型 |
《泰坦尼克号》 |
3 |
104 |
爱情片 |
《夏洛特烦恼》 |
2 |
100 |
爱情片 |
《从你的全世界路过》 |
1 |
81 |
爱情片 |
《战狼2》 |
101 |
10 |
动作片 |
《变形金刚5》 |
99 |
5 |
动作片 |
《猩球崛起3》 |
98 |
2 |
动作片 |
解释2:第二句:当输入没有标签的新数据(新数据:测试集中的数据)后
电影名称 |
打斗镜头 |
接吻镜头 |
电影类型 |
未知电影 |
18 |
90 |
预测 |
解释3:第三句:将新数据的每个特征与训练集中所有数据对应的特征进行相似性比较
由于每个样本只有两个属性,因此采用和例子1相同的方法来比较两个样本间的相似性,即:将该数据映射到二维坐标平面上,比较两点间的距离的大小。
电影名称 |
电影类型 |
与未知电影的距离 |
《泰坦尼克号》 |
爱情片 |
20.5(3) |
《夏洛特烦恼》 |
爱情片 |
18.7(1) |
《从你的全世界路过》 |
爱情片 |
19.2(2) |
《战狼2》 |
动作片 |
115.3(4) |
《变形金刚5》 |
动作片 |
117.4(5) |
《猩球崛起3》 |
动作片 |
118.9(6) |
第四句:选择训练集中前K个最相似(距离最小)的数据,提取训前K个最相似的数据的分类标签,
如果k = 3,则分别提取《泰坦尼克号》、《夏洛特烦恼》、《从你的全世界路过》三个数据的电影类型,分别是爱情片、爱情片、爱情片。
第五句:选择这K个最相似数据中出现次数最多的类别标签,作为新数据的类别标签
爱情片出现次数 |
动作片出现次数 |
3 |
0 |
未知电影的电影类型为:爱情片
小结 1:算法描述
基于前面两个简单例子,对K近邻概念定义中的每一句话进行了解释。 下面通过前面两个例子给出K近邻算法的正式化描述如下。
接下来,将根据该通过一个对UCI上的具体数据集的实验来进一步说明该算法。
2、通过UCI中的数据集来解释
数据集:mushroom数据集
1、数据集介绍:
蘑菇数据集中包括两类蘑菇,一类是有毒蘑菇,一类是无毒蘑菇。每个蘑菇有22个属性,介绍如下:
标签:有毒 = 1,无毒 = 2
属性1. cap-shape: bell=3, conical=4, convex=5, flat=6 , knobbed=7, sunken=8
属性2. cap-surface: fibrous=9, grooves=10, scaly=11, smooth=12
属性3.cap-color:brown=13, buff=14, cinnamon=15, gray=16, green=17, pink=18,
purple=19, red=20, white=21, yellow=22
.........
属性22.
2、具体数据如下所示:
2 6 10 16 23 28 34 36 39 44 53 56 59 63 69 76 85 86 90 93 98 110 116
1 3 11 16 24 29 34 36 39 42 52 56 61 66 70 77 85 86 90 95 101 110 117
2 6 10 17 23 28 34 36 39 44 53 56 59 63 69 78 85 86 90 93 99 110 116
1 3 10 16 24 29 34 36 39 43 52 56 61 66 70 77 85 86 90 95 101 110 117
1 3 9 16 24 30 34 37 38 46 52 56 59 63 67 76 85 86 90 93 99 107 116
数据处理
为了方便计算,在输入数据之前需要对数据进行处理,采用Python语言处理如下:
属性表示X:
[[ 3. 9. 13. ..., 98. 107. 113.]
[ 3. 9. 14. ..., 99. 108. 114.]
[ 4. 9. 15. ..., 99. 108. 115.]
...,
[ 6. 9. 13. ..., 102. 110. 117.]
[ 7. 10. 17. ..., 102. 110. 119.]
[ 6. 9. 17. ..., 102. 110. 119.]]
标签表示Y:
[1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, ......]
输入1:训练数据集
T= {(x1,y1),(x2,y2),(x3,y3),(x4,y4),......(xN,yN)
其中,xi为实例的特征向量,yi为实例的类别,i=1,2...N。
例如:
x1 = (6 10 16 23 28 34 36 39 44 53 56 59 63 69 76 85 86 90 93 98 110 116)
y1= 2
经过处理后输入的是:T={(X,Y)}
本次实验使用了4858个数据作为训练集,正反例比为1:1。
输入2:测试集
测试集由2000个数据组成,正反例比为1:1。
输出:测试集中每个实例x所属的类y
(1).根据给定的距离度量,在训练集T中找出与测试数据x最邻近的K个点,涵盖这个K个点的x的领域记作Nk(x)
距离度量:欧式距离
K值选取:k = 5
(2)在Nk(x)中根据分类决策规则(如:多数表决)决定x的类别y
3、K-近邻的三要素
讲解 ‘1.1抽象举例解释’ 时遗留的三个问题:
1:相似性比较方法有哪些?
2:k的值设定多少才合适?
3:多数表决规则怎样通过数学来解释?
分别对应着K近邻模型的三个基本要素:
1.距离度量(即:相似度度量)
2.K值得选择
3.分类决策规则
接下来分别对这三个基本要素进行解释说明:
3.1 距离度量
K近邻模型的特征空间一般是n维实数向量空间,使用的距离可以使欧式距离,也是可以是其它距离(曼哈顿距离、 切比雪夫距离......等)
1. 欧氏距离
最常见的两点之间或多点之间的距离表示法,又称之为欧几里得度量,它定义于欧几里得空间中,如点 x = (x1,...,xn) 和 y = (y1,...,yn) 之间的距离为:
二维平面上两点a(x1,y1)与b(x2,y2)间的欧式距离:
三维空间两点a(x1,y1,z1)与b(x2,y2,z2)间的欧式距离
2.曼哈顿距离:
通俗来讲,想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。而实际驾驶距离就是这个“曼哈顿距离”,此即曼哈顿距离名称的来源, 同时,曼哈顿距离也称为城市街区距离(City Block distance)。
(1)二维平面两点a(x1,y1)与b(x2,y2)间的曼哈顿距离
d12 = |x1-x2|+|y1-y2|
(2)两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的曼哈顿距离
本次实验分别采用了欧式距离和曼哈顿距离来进行,下面给出采用两种不同距离对样本正确率所产生的影响。
曼哈顿距离和欧式距离对比分析
分析:
1、当K=1或2时, 使用曼哈顿距离和欧式距离对测试数据的正确率是相同的。
2、从整体数据的准确率来看,使用曼哈顿距离比使用欧式距离得到的数据准确率要高。
3、从K的特殊取值来看,当K= 4时,使用欧式距离得到的准确率要比使用曼哈顿得到的准确率高。
结论:不同的距离度量方法产生的效果不同,通常情况下采用欧式距离来计算。
3.2 K值选择
K值的选择会对K近邻算法的结果产生重大影响。
如果选择较小的K值,就相当于用较小的邻域中的训练实例进行预测,只有与输入实例较近的训练实例才会对预测结果起作用。但缺点是预测结果会对邻近的实例点非常敏感。如果邻近的实例点恰好是噪声,预测就会出错。
如果选择较大的K值,与输入实例较远的训练实例也会对预测结果起作用,
此时,误差将会增大。
如果K = N。那么无论输入实例是什么,都将预测它属于在训练实例中最多的类。
总结:基于前人经验,在一般情况下,K的取值在1到20之间。
3.2不同K值范围的准确率
为了验证前人经验的准确性,此次实验分别画出了K从1到20和K从1到50区间内不同取值时的准确率。如下图所示:
分析:
1.对比两幅图,当K=4时,使用K近邻对测试数据进行实验的准确率最高,效果最好。
2.从右图中可以看到,1到25区间内,准确率呈整体下降趋势,在30左右时,虽然有所回升,但是整体还是呈下降趋势。
总结:前人经验是可信的。K值一般可以取1到20之间的整数。
3.3 分类决策
K近邻中的分类决策规则往往是多数表决,即由输入实例的k个近邻的训练实例中的多数类决定输入实例的类。
多数表决规则有如下解释:
如果分类函数为
那么误分类的概率是
对给定的实例x,其最近邻的k个训练实例点构成集合Nk(x),如果涵盖Nk(x)的区域的类别是cj ,那么误分率是
要是误分率最小即经验风险最小,就要使
最大,所以多数表决规则等于经验风险最小化。
总结
1、本次汇报首先给出K近邻算法的定义,然后通过抽象化和现实中电影类型2个例子对定义中的每一句话进行了解释。
2、然后给出了K近邻算法的正式算法描述,使用UCI上的蘑菇数据集进行了大量实验。画出了使用曼哈顿距离和欧式距离所产生的不同准确率的散点图,画出了K的不同取值范围的准确率的散点图。
3、根据对散点图的分析,得出了一些关于距离度量和K值选择的结论,最后解释了分类决策中多数表决规则。至此,K近邻算法的三个基本要素已经逐一解释完毕。
代码部分(代码仅供参考)
1、数据处理
from numpy import * def createDataset(fileName): fr = open(fileName) read_line = fr.readlines() number_line = len(read_line) data_Mat = zeros((number_line,22)) label_Mat = [] index = 0 for line in read_line: line = line.strip() splitLine = line.split( ) data_Mat[index,:]=splitLine[1:] label_Mat.append(int(splitLine[0])) index +=1 return data_Mat , label_Mat data_Mat, label_Mat = createDataset('Test_Data.dat') n=0 for i in range(0,len(label_Mat)): if label_Mat[i] == 1: n+=1 print(n) print(data_Mat) print(label_Mat)2、KNN分类器
from numpy import * import operator from A1_dataSet import createDataset def classify(inX , dataSet , labels ,k): dataSetsize = len(dataSet) diffMat = tile(inX, (dataSetsize,1)) diffMat1 = diffMat-dataSet sqDiffMat = diffMat1**2 sqDistances = sqDiffMat.sum(axis=1) distances = sqDistances**0.5 print(distances) 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] data_Mat, label_Mat = createDataset('Train_Data.dat') inX = [6,9,13,24,32,34,36,38,48,53,58,61,66,67,77,85,86,90,94,102,110,119] Class= classify(inX ,data_Mat, label_Mat,100) print(Class)3、不同K值得影响
from numpy import *
from A1_dataSet import createDataset
from A3_countError import countError
def dif_K(k):
Train_data, Train_label = createDataset('chess_TrainData.dt')
Test_data, Test_label = createDataset('chess_TestData.dt')
num_right = zeros((k,3))
best_K = 0
for i in range(1,k+1):
Error, Right_Rat=countError(Test_data, Test_label, Train_data, Train_label, i)
num_right[i-1,0] = i
num_right[i-1,1] = Error
num_right[i-1,2] = Right_Rat
if best_K < Right_Rat:
best_K=Right_Rat
return num_right,best_K
num_right,best_K = dif_K(20)
print(num_right)
print(best_K)
4、计算错误率
from numpy import * from A1_dataSet import createDataset from A2_KNN import classify def countError(Test_data,Test_label, Train_data,Train_label,k): Error = 0 index = 0 pred_Mat = [] for data in Test_data: pred_label = classify(data, Train_data,Train_label,k) pred_Mat.append(pred_label) if pred_label != Test_label[index]: Error+=1 index+=1 Right_Rat = 1-Error /len(Test_label) return Error,Right_Rat Train_data, Train_label =createDataset('Train_Data.dat') Test_data,Test_label = createDataset('Test_Data.dat') Error,ErrorRat = countError(Test_data,Test_label, Train_data,Train_label,10) print(Error) print(ErrorRat)
5、画图
import matplotlib import matplotlib.pyplot as plt from different_K import dif_K num_right,best_K = dif_K(50) fig = plt.figure() ax = fig.add_subplot(111) ax.set_title("The Influence of K") plt.xlabel('K') plt.ylabel('Accuracy') ax.scatter(num_right[:,0],num_right[:,2]) plt.show()