当前位置:   article > 正文

机器学习算法——k-近邻算法_k近邻算法

k近邻算法

前言

        K近邻算法是一种简单而有效的算法,它不需要对数据进行显式的训练,因此适用于小规模数据集和非线性问题。是学习和理解机器学习基础知识的重要算法之一,也可以作为其他机器学习算法的基准进行比较和评估。

一、k-近邻算法     

1、介绍        

        k-近邻算法(k-Nearest Neighbour algorithm),又称为KNN算法。KNN的工作原理:给定一个已知标签类别的训练数据集,输入没有标签的新数据后,在训练数据集中找到与新数据最邻近的k个实例,如果这k个实例的多数属于某个类别,那么新数据就属于这个类别。

可以简单理解为:由那些离X最近的k个点来投票决定X归为哪一类

        下面我们通过一个简单的小例子来了解一下k-近邻算法:

                                       

图1-1

        图1-1是一个很基础的knn算法模型。有两类不同的样本数据,分别用蓝色的小正方形和红色的小三角形表示,而图正中间的那个绿色的国所标示的数据则是待分类的数据。

        问题:图中的绿色的圆属于哪一类?

        如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
        如果K=5,绿色国点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。

2、距离公式

        在实现k-近邻算法中,我们经常要算出未知类别与样本中其它已知类别的距离,将它们进行排序,然后根据k的取值来判断未知样本的类别。

        距离公式有很多个,本篇博客着重使用欧式距离公式。

欧式距离公式(Euclidean Distance)

        (1)、二维平面:

假设二维平面有两个点:a(x_{1},y_{1}),b(x_{2},y_{2})

                               

        (2)、三维平面:

假设三维平面有两个店:a(x_{1},y_{1},z_{1}),b(x_{2},y_{2},z_{1})

     

        (3)、n维平面:

n维空间有两个点:a(x_{11},x_{12},...x_{1n}),b(x_{21},x_{22},...x_{2n})

        接下来通过一个小例子来使用距离公式解决问题:

电影名称打斗镜头接吻镜头电影类型
泰坦尼克号1101爱情片
后来的我们589爱情片
前任31297爱情片
战狼1129动作片
战狼21085动作片
唐人街探案1158动作片
2467

        我们将表中已有数据作为样本数据,打斗镜头和接吻镜头作为数据特征。我们用图像的方式显示出来:

图1-2

        现在我们计算未知电影与样本集中其它电影的距离,计算结果位于下面表格:

电影名称与未知电影的距离
泰坦尼克号20.5
后来的我们18.7
前任319.8
战狼115.3
战狼2117.4
唐人街探案118.9

        现在我们得到了样本集中所有电影与位置电影的距离,按照距离递增排序,可以找到k个距离最近的电影。

        比如说我们假定k=3,则最近的电影分别为:泰坦尼克号、后来的我们、前任3。因此未知电影属于爱情片。因此k的取值在k-近邻算法中是非常重要的,它间接影响到了未知样本类别的判断,所以我们对于k的取值一定要谨慎。

3、k-近邻算法的一般流程

流程:

(1)、收集数据:可以使用任何方法

(2)、准备数据:距离计算所需要的数值

(3)、分析数据:可以使用任何方法

(4)、训练算法:此步骤不适用于k-近邻算法

(5)、测试算法:计算错误率

(6)、使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入的数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。

二、k-近邻算法案例——医用判断良性恶性肿瘤

        接下来我们通过一个简单案例来深入学习k-近邻算法

问题背景

       医学上判断肿瘤需要通过radius (半径), texture(纹理), perimeter(周长), area(面积), smoothness(光滑度), symmetry(对称性), compactness(紧凑度), fractal_dimension(分形维度)等数据来判断肿瘤是否为恶性,现在有一组数据,请用knn方法来进行分析肿瘤的良性恶性(良性肿瘤用“B”,恶性肿瘤用“M”表示)

数据展示

iddiagnosis_resultradiustextureperimeterareasmoothnesscompactnesssymmetryfractal_dimension
1M23121519540.1430.2780.2420.079
2B91313313260.1430.0790.1810.057
3M212713012030.1250.160.2070.06
4M1416783860.070.2840.260.097

数据处理

  1. # 读取csv文件,将每行数据存储为一个字典,并将所有字典存储到列表中
  2. with open('Prostate_Cancer.csv') as file:
  3. reader = csv.DictReader(file)
  4. datas = [row for row in reader]
  5. # 对数据进行随机排序
  6. random.shuffle(datas)
  7. # 选取1/3的数据作为测试集,其余作为训练集
  8. n = len(datas)//3
  9. test_set = datas[0:n]
  10. train_set = datas[n:]

计算距离

  1. # 返回两个数据点之间的欧几里得距离
  2. def distance(d1,d2):
  3. res = 0
  4. for key in ("radius","texture","perimeter","area",
  5. "smoothness","compactness","symmetry","fractal_dimension"):
  6. res += (float(d1[key])-float(d2[key])) ** 2
  7. return res ** 0.5

knn分类器实现

  1. # 设定k值
  2. k = 4
  3. # KNN分类器
  4. def knn(data):
  5. # 计算测试数据和每个训练数据之间的距离,并将结果存储到一个列表中
  6. res = [
  7. {"result":train["diagnosis_result"],"distance":distance(data,train)}
  8. for train in train_set
  9. ]
  10. # 将结果按照距离从小到大排序
  11. res = sorted(res, key=lambda item:item['distance'])
  12. # 取前K个距离最近的数据
  13. res2 = res[0:k]
  14. # 加权平均,将离测试数据更近的数据点所属类别的贡献权重更高
  15. result = {'B':0,'M':0}
  16. # 计算所有数据点到测试数据的距离之和
  17. sum_dist = 0
  18. for r1 in res2:
  19. sum_dist += r1['distance']
  20. # 逐个分类累加贡献权重(结果为'B'或'M')
  21. for r2 in res2:
  22. result[r2["result"]] += 1-r2["distance"]/sum_dist
  23. if result['B'] > result['M']:
  24. return 'B'
  25. else:
  26. return 'M'

测试集预测

  1. # 求正确率
  2. correct = 0
  3. for test in test_set:
  4. result = test['diagnosis_result']
  5. result2 = knn(test)
  6. # 如果预测结果正确,计数器加1
  7. if result == result2:
  8. correct = correct + 1;
  9. print("正确率为:" + str(correct/len(test_set)))

预测结果

图2-1

        多次改变k值可以发现,k取5的时候正确率最高。

完整代码

  1. import csv
  2. import random
  3. # 读取csv文件,将每行数据存储为一个字典,并将所有字典存储到列表中
  4. with open('Prostate_Cancer.csv') as file:
  5. reader = csv.DictReader(file)
  6. datas = [row for row in reader]
  7. # 对数据进行随机排序
  8. random.shuffle(datas)
  9. # 选取1/3的数据作为测试集,其余作为训练集
  10. n = len(datas)//3
  11. test_set = datas[0:n]
  12. train_set = datas[n:]
  13. # 返回两个数据点之间的欧几里得距离
  14. def distance(d1,d2):
  15. res = 0
  16. for key in ("radius","texture","perimeter","area",
  17. "smoothness","compactness","symmetry","fractal_dimension"):
  18. res += (float(d1[key])-float(d2[key])) ** 2
  19. return res ** 0.5
  20. # 设定k值
  21. k = 5
  22. # KNN分类器
  23. def knn(data):
  24. # 计算测试数据和每个训练数据之间的距离,并将结果存储到一个列表中
  25. res = [
  26. {"result":train["diagnosis_result"],"distance":distance(data,train)}
  27. for train in train_set
  28. ]
  29. # 将结果按照距离从小到大排序
  30. res = sorted(res, key=lambda item:item['distance'])
  31. # 取前K个距离最近的数据
  32. res2 = res[0:k]
  33. # 加权平均,将离测试数据更近的数据点所属类别的贡献权重更高
  34. result = {'B':0,'M':0}
  35. # 计算所有数据点到测试数据的距离之和
  36. sum_dist = 0
  37. for r1 in res2:
  38. sum_dist += r1['distance']
  39. # 逐个分类累加贡献权重(结果为'B'或'M')
  40. for r2 in res2:
  41. result[r2["result"]] += 1-r2["distance"]/sum_dist
  42. if result['B'] > result['M']:
  43. return 'B'
  44. else:
  45. return 'M'
  46. # 求正确率
  47. correct = 0
  48. for test in test_set:
  49. result = test['diagnosis_result']
  50. result2 = knn(test)
  51. # 如果预测结果正确,计数器加1
  52. if result == result2:
  53. correct = correct + 1;
  54. print("正确率为:" + str(correct/len(test_set)))

三、总结

       KNN算法是一种简单但有效的分类算法,尤其适用于样本数据不平衡、数据分布不规则的情况。它为初学者提供了一个很好的入门点,并且在一些小规模的问题中具有良好的效果。对于分类问题,通过投票的方式确定待分类样本所属的类别;对于回归问题,采用平均值等方法来预测待分类样本的数值。K近邻算法的优点在于简单易懂,且对于非线性、非参数化模型适用。但是它的缺点是需要大量的计算和存储空间,在处理高维度数据时效果较差,并且对于样本分布不均匀及噪声比较大的数据集容易受到干扰,因此在使用过程中需要多加注意。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/767107
推荐阅读
相关标签
  

闽ICP备14008679号