机器学习算法(一)——kNN算法

☆樱花仙子☆ 提交于 2020-02-27 05:42:50

一、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);无数据输入假定;
  • 对异常值不敏感

缺点

  • 计算复杂性高;空间复杂性高;
  • 样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
  • 一般数值很大的时候不用这个,计算量太大。但是单个样本又不能太少,否则容易发生误分。
  • 最大的缺点是无法给出数据的内在含义。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!