分类算法 -- KNN算法 (理论与python实现)

2020-12-28 11:19:02 浏览数 (1)

参考链接: K means聚类Python–简介

分类算法 – KNN算法 

KNN(K-Nearest Neighbor)是一个分类算法,属于有监督学习。 KNN思想的核心在于:近朱者赤,近墨者黑,根据新样本的k个最近邻居来判定其类别。 

1. 理论说明 

1.1 算法概论 

假设我们已知n个样本的特征和标签(即所属分类),并以此作为样本集A。 

当输入一个没有标签的样本b时,我们可以通过比较新样本b与样本集A中的数据对应的特征,然后提取出最为相似的k个数据。 

最后我们选取k个最相似的数据中出现次数最多的分类,作为新数据的分类。 

1.2 算法步骤 

Step 1:计算已知类别的样本集A中的所有样本与新样本b之间的距离 Step 2:按照距离的递增次序,对样本集A中的样本进行排序 Step 3:选取与当前样本b距离最近的k个样本 Step 4:确定这k个样本所在类别的出现频率 Step 5:返回这k个样本中出现频率最高的类别作为当前样本b的预测分类 

1.3 算法优劣 

优势:精度高、对异常值不敏感、算法思想简单、比较适合多分类问题 劣势:计算成本高,中间步骤的储存成本高,对大规模数据不是很友好 

1.4 详细问题 

①k的选择 

和聚类分析中的K-means算法相同,k的选择也是KNN方法的难点所在。 

若k很小,结果容易受到噪声和极端值的影响;若k很大,则在选取的近邻中又包含很多无关的点,增加计算量的同时也影响计算结果。 根据经验,我们一般会让k小于样本集A中样本数量的平方根 

②距离的度量 

在算法中,我们明确说明了要计算已知类别的样本集A中的所有样本与新样本b之间的距离。那我们需要选择哪种距离呢? 

当样本特征的单位相同、方差差距不大时,此时选择欧式距离是合理的; 当样本特征的单位不同,并且方差差距较大时,选择欧式距离会更加关注方差大的特征而忽视方差较小的特征,所以此时选取马氏距离效果较好。 

2.python实现 

2.1 KNN函数(不调包) 

此处,python实现KNN算法,不使用python包sklearn 使用的是欧式距离,并且各个样本权重均相同 

import pandas as pd

import numpy as np

from collections import Counter

#导入数据

data = pd.read_excel('........xlsx')

train_X = data[['','',''...]] #按列选择自变量

train_Y = data[['..']] #按列选择因变量

test_X = [] #设置待分类样本

#定义KNN函数,直接返回分类

def KNN(train_X,train_Y,test_X,k):  

    '''需要输入的数据包括训练集的自变量、训练集的因变量、待测试的数据、k'''

    '''首先计算欧式距离,并对其排序'''

    dist = (np.tile(test_X,(train_X.shape[0],1)) - train_X)**2

    distances = (dist.sum(axis=1))**0.5  #计算欧式距离,并且使各个观测的权重相同

    sorteddist = distances.argsort() #将数据从小到大排序,返回的是编号

    '''选出距离前k小的数据的类别,存放在count中'''

    count = []         

    for i in range(k):

        count.append(train_Y[sorteddist[i]])  

    '''返回出现次数最多的类别'''

    return Counter(count).most_common(1)[0][0] 

2.2 python实例 

此处,我们将使用sklearn包 

2.2.1 数据简介 

本案例使用的是sklearn包中的鸢尾花数据集 数据包含三种鸢尾花的四个特征:花萼长度(cm)、花萼宽度(cm)、花瓣长度(cm)、花瓣宽度(cm)。 数据共有150个观测,我们将其以8:2分成训练集和测试集 

2.2.2 实现环境 

python 3.7 & sklearn 

2.2.3 实现代码 

from sklearn.model_selection import train_test_split

from sklearn.neighbors import KNeighborsClassifier 

from sklearn import datasets

#导入数据

iris = datasets.load_iris()

iris_X = iris.data

iris_Y = iris.target

#将数据分成训练集和测试集,比例为:80%和20%

iris_train_X , iris_test_X, iris_train_Y ,iris_test_Y = train_test_split(

iris_X, iris_Y, test_size=0.2,random_state=0)

#设置KNN算法的参数

KNN =KNeighborsClassifier(algorithm='auto', #在KNN中使用的算法,其他选项还有ball_tree,kd_tree,和brute

                          leaf_size=30,   #当使用和树有关的算法时的叶子数量

                          metric='minkowski',p=2, #使用的是明可夫斯基距离中的欧式距离

                          metric_params=None,

                          n_jobs=1,  #并行计算的线程数量

                          n_neighbors=3, #分成5类(默认)

                          weights='distance' #距离计算中使用的权重,distance表示按照距离的倒数加权,uniform表示各样本权重相同

                          )

#将KNN算法应用在训练集上

KNN.fit(iris_train_X, iris_train_Y)

#将结果应用于测试集中

predict = KNN.predict(iris_test_X)

print(predict)

#计算模型的正确率

print(KNN.score(iris_test_X, iris_test_Y))

#正确率为100%              

KNN算法的参数选择 

2.2.4 本例总结 

本例中最重要的就是KNN中参数的选择: algorithm=auto;weights=uniform时,正确率为0.9666 algorithm=auto;weights=distance时,正确率为1.0000 

本数据集的问题在于样本量太小

0 人点赞