一、kNN算法简介
1-1、kNN算法简介
kNN算法,即k最近邻算法(k-NearestNeighbor)是数据挖掘算法中最基础的算法之一。所谓k最近邻就是k个最近的邻居的意思。
1-2、kNN算法思想
kNN是一种分类(classification)算法,它输入基于实例的学习(instance-based learning),属于懒惰学习(lazy learning)。即kNN没有显式的学习过程,也就是说没有训练阶段,数据集事先已有了分类和特征值,待收到新样本后直接进行处理。与急切学习(eager learning)相对应。
kNN是通过测量不同特征值之间的距离进行分类。
1-3、kNN算法工作机制
kNN工作机制非常简单:给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。
- 通常在分类任务中使用“投票法”,即选择这k个样本中出现最多的类别标记作为预测结果;
- 在回归任务中可使用“平均法”,即将这k个样本的实值输出标记的平均值作为预测结果;
- 还可基于距离的远近进行加权平均或加权投票。
1-4、kNN算法决定要素
kNN算法使用的模型,其实是特征空间的划分。该算法主要取决于三个因素:
1. 距离度量
2. k值
3. 分类决策规则
其中,两个实例之间的距离反映其相似程度。一般使用欧氏距离计算。
因此,该算法流程如下:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
二、关于k的取值
K值得选取非常重要,因为:
如果当K的取值过小时,一旦有噪声得成分存在们将会对预测产生比较大影响,例如取K值为1时,一旦最近的一个点是噪声,那么就会出现偏差,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
如果K的值取的过大时,就相当于用较大邻域中的训练实例进行预测,学习的近似误差会增大。这时与输入目标点较远实例也会对预测起作用,使预测发生错误。K值的增大就意味着整体的模型变得简单;
如果K==N的时候,那么就是取全部的实例,即为取实例中某分类下最多的点,就对预测没有什么实际的意义了;
K的取值尽量要取奇数,以保证在计算结果最后会产生一个较多的类别,如果取偶数可能会产生相等的情况,不利于预测。
常用的方法是从k=1开始,使用检验集估计分类器的误差率。重复该过程,每次K增值1,允许增加一个近邻。选取产生最小误差率的K。
一般k的取值不超过20,上限是n的开方,随着数据集的增大,K的值也要增大。
2-1、距离度量
常用的距离度量是欧式距离、曼哈顿距离、余弦值、相关度。
欧式距离:
曼哈顿距离:
欧氏距离与曼哈顿距离图解:
三、kNN算法示例
假设我们对电影进行分类,选取两个因素作为其分类依据,如图所示:
我们可以从散点图大致推断,这个红色圆点标记的电影可能属于动作片,因为距离已知的那两个动作片的圆点更近。k-近邻算法用什么方法进行判断呢?没错,就是距离度量。
这个电影分类的例子有2个特征,也就是在2维实数向量空间,可以使用我们高中学过的两点距离公式计算距离,如图所示。
通过计算,我们可以得到如下结果:
- (101,20)->动作片(108,5)的距离约为16.55
- (101,20)->动作片(115,8)的距离约为18.44
- (101,20)->爱情片(5,89)的距离约为118.22
- (101,20)->爱情片(1,101)的距离约为128.69
通过计算可知,红色圆点标记的电影到动作片 (108,5)的距离最近,为16.55。如果算法直接根据这个结果,判断该红色圆点标记的电影为动作片,这个算法就是最近邻算法。
比如,现在我这个k值取3,那么在电影例子中,按距离依次排序的三个点分别是动作片(108,5)、动作片(115,8)、爱情片(5,89)。在这三个点中,动作片出现的频率为三分之二,爱情片出现的频率为三分之一,所以该红色圆点标记的电影为动作片。
四、kNN算法实现(Python实现)
此处使用西瓜书的课后习题,作为练习题目。
- 编程实现k近邻分类器(数据集:西瓜数据集3.0a)。
实现knn算法
def predict_kNN(X_train,y_train,X_test,k):
#获得训练集、测试集长度
X_train_len = len(X_train)
X_test_len = len(X_test)
#预测结果储存
predict_y = []
for test_data in range(X_test_len):
dis_test = []
for train_data in range(X_train_len):
dis_train = abs(sum(X_train[train_data,:]-X_test[test_data,:]))
dis_test.append(dis_train**0.5)
# 升序进行快排,返回原数组的下标
dis_test = np.array(dis_test)
sort_id = dis_test.argsort()
dic={}
for i in range(k):
vlable=y_train[sort_id[i]] #为对应的标签记数
dic[vlable]=dic.get(vlable,0)+1
#寻找vlable代表的标签,如果没有返回0并加一,如果已经存在返回改键值对应的值并加一
max = 0
for index, v in dic.items(): #.items 返回所有的键值对
if v > max:
max = v
maxIndex = index
predict_y.append(int(maxIndex))
print("---------------data------------------:")
print(y)
print("\n"+"--------------predict----------------:")
print(predict_y)
if __name__ == "__main__":
#获取数据集
dataset = pd.read_csv('./watermelon01.csv', delimiter=",")
watermelon_data = dataset.values
# 从数据集中分离出测试集和结果集
X = watermelon_data[:,:2]
y = watermelon_data[:,-1]
# 查看数据
#display(type(X),type(y))
#display(X,y)
X_test = X[[0,3,5,7,9,11,13,15],:2]
#k值取2
predict_kNN(X,y,X_test,2)
结果如下:
五、kNN算法实现(调用sk-learn)
from sklearn.neighbors import KNeighborsClassifier
dataset = pd.read_csv('./watermelon01.csv', delimiter=",")
watermelon_data = dataset.values
# 从数据集中分离出测试集和结果集
X = watermelon_data[:,:2]
y = watermelon_data[:,-1]
X_test = X[[0,3,5,7,9,11,13,15],:2]
knn = KNeighborsClassifier(n_neighbors=2)
knn.fit(X,y)
knn.predict(X_test)
结果如下:
六、kNN算法优缺点
优点
- 简单好用,容易理解,精度高,理论成熟,既可以用来做分类也可以用来做回归;
- 可用于数值型数据和离散型数据;
- 训练时间复杂度为O(n);无数据输入假定;
- 对异常值不敏感
缺点
- 计算复杂性高;空间复杂性高;
- 样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
- 一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。
- 最大的缺点是无法给出数据的内在含义。
来源:oschina
链接:https://my.oschina.net/u/3938912/blog/3171672