从零开始的AI·吃透kNN算法,学完我悟了(附实例代码)

Posted 有理想、有本领、有担当的有志青年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始的AI·吃透kNN算法,学完我悟了(附实例代码)相关的知识,希望对你有一定的参考价值。

从零开始的AI系列

从零开始的AI·机器学习の基本概念



前言

本文理论部分基于Peter Harrington的《机器学习实战》一书

kNN(k- Nearest Neighbor)即k-近邻算法,最初由 Cover和Hart于1968年提出,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路非常简单直观:如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

如果觉得AI学习枯燥,可以选择看一下这个老哥做的网站,趣味性直接拉满>>人工智能教程


一、权衡利弊

  • 优点:精度高、对异常值不敏感、无数据输入假定。
  • 缺点:计算复杂度高、空间复杂度高。
  • 适用数据范围:数值型和标称型。
  • 应用:分类回归

二、整体感知

图解kNN

在这里插入图片描述
在上图中,五角星方块分别代表不同特征的数据,问号 是需要我们预测的数据。现我们假设 k=5,即以距离问号最近5个数据的特征来确定该问号的特征。由此可知,问号①被预测为五角星,问号②被预测为方块。但是,当数据足够复杂时,k的值稍有变化,结果就可能不同,因此k的取值显得尤为重要。

具体实例的应用

电影可以按照题材分类,同一题材的电影具有一些公共特征。那么动作片具有哪些共有特征,使得动作片之间非常类似,而与爱情片存在着明显的差别呢?动作片中也会存在接吻镜头,爱情片中也会存在打斗场景,我们不能单纯依靠是否存在打斗或者亲吻来判断影片的类型。但是爱情片中的亲吻镜头更多动作片中的打斗场景也更频繁,基于此类场景在某部电影中出现的次数可以用来进行电影分类。基于电影中出现的亲吻、打斗出现的次数,使用k-近邻算法构造程序,我们就可以实现自动划分电影的题材类型。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
由上图可计算出距离
在这里插入图片描述
根据几个距离最小的已知电影,我们可以预测出,未知电影为爱情片

三、具体实现过程及细节

1. 数据的读取

对数据进行读取,并随机分为三类:训练集,验证集,测试集

with open('iris.csv','r') as file:  ##打开文件'iris.csv',并命名为 file
    reader = csv.DictReader(file)  
    datas = [row for row in reader]
random.shuffle(datas)  
n = len(datas)//3  

test_set = datas[0:n]  
train_set = datas[n:]  

2. K值的选择

  • 取值方式:从选取一个较小的K值开始,不断增加K值
  • 验证方式:交叉验证(将数据按照一定比例分出训练组和测试组,用测试组验证训练组得出的模型) 原理+方法

3. 距离的计算

  • 闵可夫斯基距离
    在这里插入图片描述

  • 欧氏距离
    在这里插入图片描述

  • 曼哈顿距离
    在这里插入图片描述

'''此处为欧式距离公式'''
def distance(d1, d2):
    res = 0
    feature = ("150","4","setosa","versicolor")
    for key in (feature):
        res += (float(d1[key])-float(d2[key]))**2
        return res**0.5

4. 数据的处理

'''(1)对距离排序—升序'''
    res = sorted(res, key = lambda
    item:item['distance'])#
'''(2)取前K个'''
    res2 = res[0:K]
'''(3)加权平均(距离近的比重大)'''
    result = {'0': 0, '1':0, '2': 0}
    sum = 0
    for r in res2:                
        sum+= r['distance']

    for r in res2:                
        result[r['result']] += 1 - r['distance']/sum  
    resulutCount1= sorted(result.items(),
    key=operator.itemgetter(1), reverse=True)
    return (resulutCount1[0][0])

5. 测试

利用测试集进行测试对比

correct = 0              
for test in test_set:  
    result = test['virginica']
    result2 = knn(test)
    if result  == result2:
        correct+=1

print("正确率:{:.2f}%".format(100*correct/len(test_set)))

四、封装函数的使用

  • 分类neighbors.KNeighborsClassifier
  • 预测neighbors.KNeighborsRegressor
neighbors.KNeighborsClassifier(n_neighbors=5, weights='uniform',p=2, metric='minkowski',)
n_neighbors:用于指定近邻样本个数K,默认为5
weights:用于指定近邻样本的投票权重,默认为'uniform',表示所有近邻样本的投票权重一样;如果为'distance',则表示投票权重与距离成反比,即近邻样本与未知类别的样本点距离越远,权重越小,反之,权重越大
metric:用于指定距离的度量指标,默认为闵可夫斯基距离
p:当参数metric为闵可夫斯基距离时,p=1,表示计算点之间的曼哈顿距离;p=2,表示计算点之间的欧氏距离;该参数的默认值为2
#适用于最新版本python,复制就可以跑的代码!!!
import csv
import random
#读取
with open('train.csv','r') as file:
    reader=csv.DictReader(file)
    datas=[row for row in reader]

#分组
random.shuffle(datas)
n=len(datas)//10

test_set=datas[0:8*n]
train_set=datas[8*n:]

#KNN
#距离
def distance(d1,d2):
    res=0
    for key in ("radius","texture"):
        res+=(float(d1[key])-float(d2[key]))**2

    return res**0.5

K=1
def knn(data):
#1.距离
   res=[
       {"result":train['diagnosis_result'],"distance":distance(data,train)}
       for train in train_set
   ]

#2.排序--升序
   res=sorted(res, key=lambda item:item['distance'])

#3.取前K个
   res2=res[0:K]

#4.加权平均
   result={'0':0,'1':0}
#总距离
   sum=0
   for r in res2:
    sum+=r['distance']

    for r in res2:
        result[r['result']]+=1-r['distance']/sum

    if result['0']>result['1']:
        return '0'
    else:
        return'1'
#测试阶段
correct=0
for test in test_set:
    result=test['diagnosis_result']
    result2=knn(test)

    if result==result2:
        correct+=1

print('准确率{:.2f}%'.format(100*correct/len(test_set)))
knn(test_set[0]

以上是关于从零开始的AI·吃透kNN算法,学完我悟了(附实例代码)的主要内容,如果未能解决你的问题,请参考以下文章

从零开始的AI·决策树原来这么好理解(附实例代码)

VIVO一面竟然翻车,含泪整理了这些Java面经,看完我悟了

在知乎逮到一个腾讯10年老Java开发,聊过之后我悟了

读完《演进式架构》我悟了!!!

读完《演进式架构》我悟了!!!

怒肝 200 道 Python 面试题,我悟了!