机器学习之KNN最邻近分类算法

KNN算法简介

KNN(K-Nearest Neighbor)最邻近分类算法是数据挖掘分类(classification)技术中最简单的算法之一,其指导思想是”近朱者赤,近墨者黑“,即由你的邻居来推断出你的类别。



KNN最邻近分类算法的实现原理:为了判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则(majority-voting),将未知样本与K个最邻近样本中所属类别占比较多的归为一类。

以上就是KNN算法在分类任务中的基本原理,实际上K这个字母的含义就是要选取的最邻近样本实例的个数,在 scikit-learn 中 KNN算法的 K 值是通过 n_neighbors 参数来调节的,默认值是 5。

如下图所示,如何判断绿色圆应该属于哪一类,是属于红色三角形还是属于蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被判定为属于红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆将被判定为属于蓝色四方形类。



由于KNN最邻近分类算法在分类决策时只依据最邻近的一个或者几个样本的类别来决定待分类样本所属的类别,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

KNN算法的关键:

(1) 样本的所有特征都要做可比较的量化

若是样本特征中存在非数值的类型,必须采取手段将其量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。

(2) 样本特征要做归一化处理

样本有多个参数,每一个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些 scale 处理,最简单的方式就是所有特征的数值都采取归一化处置。

(3) 需要一个距离函数以计算两个样本之间的距离

通常使用的距离函数有:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量情况下,汉明距离可以用来作为度量。通常情况下,如果运用一些特殊的算法来计算度量的话,K近邻分类精度可显著提高,如运用大边缘最近邻法或者近邻成分分析法。

以计算二维空间中的A(x1,y1)、B(x2,y2)两点之间的距离为例,欧氏距离和曼哈顿距离的计算方法如下图所示:



(4) 确定K的值

K值选的太大易引起欠拟合,太小容易过拟合,需交叉验证确定K值。

KNN算法的优点:

1.简单,易于理解,易于实现,无需估计参数,无需训练;

2. 适合对稀有事件进行分类;

3.特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好。

KNN算法的缺点:

KNN算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数,如下图所示。该算法只计算最近的邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。



该方法的另一个不足之处是计算量较大,因为对每一个待分类的文本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。

可理解性差,无法给出像决策树那样的规则。

KNN算法实现

要自己动手实现KNN算法其实不难,主要有以下三个步骤:

算距离:给定待分类样本,计算它与已分类样本中的每个样本的距离;

找邻居:圈定与待分类样本距离最近的K个已分类样本,作为待分类样本的近邻;

做分类:根据这K个近邻中的大部分样本所属的类别来决定待分类样本该属于哪个分类;

以下是使用Python实现KNN算法的简单示例:


  1. import math

  2. import csv

  3. import operator

  4. import random

  5. import numpy as np

  6. from sklearn.datasets import make_blobs


  7. #Python version 3.6.5


  8. # 生成样本数据集 samples(样本数量) features(特征向量的维度) centers(类别个数)

  9. def createDataSet(samples=100, features=2, centers=2):

  10. return make_blobs(n_samples=samples, n_features=features, centers=centers, cluster_std=1.0, random_state=8)


  11. # 加载鸢尾花卉数据集 filename(数据集文件存放路径)

  12. def loadIrisDataset(filename):

  13. with open(filename, 'rt') as csvfile:

  14. lines = csv.reader(csvfile)

  15. dataset = list(lines)

  16. for x in range(len(dataset)):

  17. for y in range(4):

  18. dataset[x][y] = float(dataset[x][y])

  19. return dataset


  20. # 拆分数据集 dataset(要拆分的数据集) split(训练集所占比例) trainingSet(训练集) testSet(测试集)

  21. def splitDataSet(dataSet, split, trainingSet=[], testSet=[]):

  22. for x in range(len(dataSet)):

  23. if random.random() <= split:

  24. trainingSet.append(dataSet[x])

  25. else:

  26. testSet.append(dataSet[x])

  27. # 计算欧氏距离

  28. def euclideanDistance(instance1, instance2, length):

  29. distance = 0

  30. for x in range(length):

  31. distance += pow((instance1[x] - instance2[x]), 2)

  32. return math.sqrt(distance)


  33. # 选取距离最近的K个实例

  34. def getNeighbors(trainingSet, testInstance, k):

  35. distances = []

  36. length = len(testInstance) - 1

  37. for x in range(len(trainingSet)):

  38. dist = euclideanDistance(testInstance, trainingSet[x], length)

  39. distances.append((trainingSet[x], dist))

  40. distances.sort(key=operator.itemgetter(1))


  41. neighbors = []

  42. for x in range(k):

  43. neighbors.append(distances[x][0])

  44. return neighbors


  45. # 获取距离最近的K个实例中占比例较大的分类

  46. def getResponse(neighbors):

  47. classVotes = {}

  48. for x in range(len(neighbors)):

  49. response = neighbors[x][-1]

  50. if response in classVotes:

  51. classVotes[response] += 1

  52. else:

  53. classVotes[response] = 1

  54. sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)

  55. return sortedVotes[0][0]


  56. # 计算准确率

  57. def getAccuracy(testSet, predictions):

  58. correct = 0

  59. for x in range(len(testSet)):

  60. if testSet[x][-1] == predictions[x]:

  61. correct += 1

  62. return (correct / float(len(testSet))) * 100.0



  63. def main():

  64. # 使用自定义创建的数据集进行分类

  65. # x,y = createDataSet(features=2)

  66. # dataSet= np.c_[x,y]


  67. # 使用鸢尾花卉数据集进行分类

  68. dataSet = loadIrisDataset(r'C:\DevTolls\eclipse-pureh2b\python\DeepLearning\KNN\iris_dataset.txt')


  69. print(dataSet)

  70. trainingSet = []

  71. testSet = []

  72. splitDataSet(dataSet, 0.75, trainingSet, testSet)

  73. print('Train set:' + repr(len(trainingSet)))

  74. print('Test set:' + repr(len(testSet)))

  75. predictions = []

  76. k = 7

  77. for x in range(len(testSet)):

  78. neighbors = getNeighbors(trainingSet, testSet[x], k)

  79. result = getResponse(neighbors)

  80. predictions.append(result)

  81. print('>predicted=' + repr(result) + ',actual=' + repr(testSet[x][-1]))

  82. accuracy = getAccuracy(testSet, predictions)

  83. print('Accuracy: ' + repr(accuracy) + '%')

  84. main()


尾花卉数据文件百度网盘下载链接: pan.baidu.com/s/10vI5p_ 密码:4und

KNN算法应用

使用KNN算法处理简单分类任务

在scikit-learn中,内置了若干个玩具数据集(Toy Datasets),还有一些API让我们可以自己动手生成一些数据集。接下来我们将使用scikit-learn的make_blobs函数来生成一个样本数量为200,分类数量为2的数据集,并使用KNN算法来对其进行分类。


  1. # 导入画图工具

  2. import matplotlib.pyplot as plt

  3. # 导入数组工具

  4. import numpy as np

  5. # 导入数据集生成器

  6. from sklearn.datasets import make_blobs

  7. # 导入KNN 分类器

  8. from sklearn.neighbors import KNeighborsClassifier

  9. # 导入数据集拆分工具

  10. from sklearn.model_selection import train_test_split


  11. # 生成样本数为200,分类数为2的数据集

  12. data=make_blobs(n_samples=200, n_features=2,centers=2, cluster_std=1.0, random_state=8)

  13. X,Y=data


  14. # 将生成的数据集进行可视化

  15. # plt.scatter(X[:,0], X[:,1],s=80, c=Y, cmap=plt.cm.spring, edgecolors='k')

  16. # plt.show()


  17. clf = KNeighborsClassifier()

  18. clf.fit(X,Y)


  19. # 绘制图形

  20. x_min,x_max=X[:,0].min()-1,X[:,0].max()+1

  21. y_min,y_max=X[:,1].min()-1,X[:,1].max()+1

  22. xx,yy=np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))

  23. z=clf.predict(np.c_[xx.ravel(),yy.ravel()])


  24. z=z.reshape(xx.shape)

  25. plt.pcolormesh(xx,yy,z,cmap=plt.cm.Pastel1)

  26. plt.scatter(X[:,0], X[:,1],s=80, c=Y, cmap=plt.cm.spring, edgecolors='k')

  27. plt.xlim(xx.min(),xx.max())

  28. plt.ylim(yy.min(),yy.max())

  29. plt.title("Classifier:KNN")


  30. # 把待分类的数据点用五星表示出来

  31. plt.scatter(6.75,4.82,marker='*',c='red',s=200)


  32. # 对待分类的数据点的分类进行判断

  33. res = clf.predict([[6.75,4.82]])

  34. plt.text(6.9,4.5,'Classification flag: '+str(res))


  35. plt.show()


程序执行后得到结果如下图所示:



使用KNN算法处理多元分类任务

接下来,我们再使用scikit-learn的make_blobs函数来生成一个样本数量为500,分类数量为5的数据集,并使用KNN算法来对其进行分类。


  1. # 导入画图工具

  2. import matplotlib.pyplot as plt

  3. # 导入数组工具

  4. import numpy as np

  5. # 导入数据集生成器

  6. from sklearn.datasets import make_blobs

  7. # 导入KNN 分类器

  8. from sklearn.neighbors import KNeighborsClassifier

  9. # 导入数据集拆分工具

  10. from sklearn.model_selection import train_test_split


  11. # 生成样本数为500,分类数为5的数据集

  12. data=make_blobs(n_samples=500, n_features=2,centers=5, cluster_std=1.0, random_state=8)

  13. X,Y=data


  14. # 将生成的数据集进行可视化

  15. # plt.scatter(X[:,0], X[:,1],s=80, c=Y, cmap=plt.cm.spring, edgecolors='k')

  16. # plt.show()


  17. clf = KNeighborsClassifier()

  18. clf.fit(X,Y)


  19. # 绘制图形

  20. x_min,x_max=X[:,0].min()-1,X[:,0].max()+1

  21. y_min,y_max=X[:,1].min()-1,X[:,1].max()+1

  22. xx,yy=np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))

  23. z=clf.predict(np.c_[xx.ravel(),yy.ravel()])


  24. z=z.reshape(xx.shape)

  25. plt.pcolormesh(xx,yy,z,cmap=plt.cm.Pastel1)

  26. plt.scatter(X[:,0], X[:,1],s=80, c=Y, cmap=plt.cm.spring, edgecolors='k')

  27. plt.xlim(xx.min(),xx.max())

  28. plt.ylim(yy.min(),yy.max())

  29. plt.title("Classifier:KNN")


  30. # 把待分类的数据点用五星表示出来

  31. plt.scatter(0,5,marker='*',c='red',s=200)


  32. # 对待分类的数据点的分类进行判断

  33. res = clf.predict([[0,5]])

  34. plt.text(0.2,4.6,'Classification flag: '+str(res))

  35. plt.text(3.75,-13,'Model accuracy: {:.2f}'.format(clf.score(X, Y)))


  36. plt.show()


程序执行后得到结果如下图所示:



使用KNN算法进行回归分析

这里我们使用scikit-learn的make_regression生成数据集来进行实验,演示KNN算法在回归分析中的表现。


  1. # 导入画图工具

  2. import matplotlib.pyplot as plt

  3. # 导入数组工具

  4. import numpy as np


  5. # 导入用于回归分析的KNN模型

  6. from sklearn.neighbors import KNeighborsRegressor

  7. # 导入数据集拆分工具

  8. from sklearn.model_selection import train_test_split

  9. # 导入数据集生成器

  10. from sklearn.datasets.samples_generator import make_regression

  11. from docutils.utils.math.math2html import LineWriter


  12. # 生成样本数为200,分类数为2的数据集

  13. X,Y=make_regression(n_samples=100,n_features=1,n_informative=1,noise=50,random_state=8)


  14. # 将生成的数据集进行可视化

  15. # plt.scatter(X,Y,s=80, c='orange', cmap=plt.cm.spring, edgecolors='k')

  16. # plt.show()

  17. reg = KNeighborsRegressor(n_neighbors=5)


  18. reg.fit(X,Y)


  19. # 将预测结果用图像进行可视化

  20. z = np.linspace(-3,3,200).reshape(-1,1)

  21. plt.scatter(X,Y,c='orange',edgecolor='k')

  22. plt.plot(z,reg.predict(z),c='k',Linewidth=3)

  23. #

  24. plt.title("KNN Regressor")


  25. plt.show()


程序执行后得到结果如下图所示:



KNN算法项目实战----酒的分类


  1. from sklearn.datasets.base import load_wine

  2. from sklearn.model_selection import train_test_split

  3. from sklearn.neighbors import KNeighborsClassifier

  4. import numpy as np


  5. # 从 sklearn的datasets模块载入数据集加载酒的数据集

  6. wineDataSet=load_wine()

  7. print(wineDataSet)

  8. print("红酒数据集中的键:\n{}".format(wineDataSet.keys()))

  9. print("数据概况:\n{}".format(wineDataSet['data'].shape))

  10. print(wineDataSet['DESCR'])


  11. # 将数据集拆分为训练数据集和测试数据集

  12. X_train,X_test,y_train,y_test=train_test_split(wineDataSet['data'],wineDataSet['target'],random_state=0)

  13. print("X_train shape:{}".format(X_train.shape))

  14. print("X_test shape:{}".format(X_test.shape))

  15. print("y_train shape:{}".format(y_train.shape))

  16. print("y_test shape:{}".format(y_test.shape))


  17. knn = KNeighborsClassifier(n_neighbors=1)

  18. knn.fit(X_train,y_train)

  19. print(knn)


  20. # 评估模型的准确率

  21. print('测试数据集得分:{:.2f}'.format(knn.score(X_test,y_test)))


  22. # 使用建好的模型对新酒进行分类预测

  23. X_new = np.array([[13.2,2.77,2.51,18.5,96.6,1.04,2.55,0.57,1.47,6.2,1.05,3.33,820]])

  24. prediction = knn.predict(X_new)

  25. print("预测新酒的分类为:{}".format(wineDataSet['target_names'][prediction]))


执行程序后打印如下结果:


  1. X_train shape:(133, 13)

  2. X_test shape:(45, 13)

  3. y_train shape:(133,)

  4. y_test shape:(45,)

  5. KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',

  6. metric_params=None, n_jobs=1, n_neighbors=1, p=2,

  7. weights='uniform')

  8. 测试数据集得分:0.76

  9. 预测新酒的分类为:['class_2']


参考书籍:《深入浅出 Python 机器学习》 作者:段小手

深圳SEO优化公司大理模板推广推荐黑河网站seo优化价格醴陵网站推广哪家好巢湖外贸网站制作推荐唐山网站建设鄂州高端网站设计多少钱曲靖网站关键词优化推荐遵义百姓网标王推广十堰品牌网站设计推荐汉中优化哪家好舟山SEO按天扣费价格醴陵网站推广系统石家庄阿里店铺运营推荐抚顺模板制作价格坑梓网站建设多少钱凉山SEO按天计费哪家好黔南企业网站制作多少钱德州网站推广报价固原优秀网站设计报价沙井营销网站哪家好阿坝营销网站报价保山网站搭建公司南充企业网站改版价格盐城网站推广多少钱秦皇岛设计公司网站推荐思茅网站定制重庆网站推广系统丹东企业网站改版哪家好资阳网站改版多少钱广元营销网站推荐歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化