KNN算法原理详解及python代码实现

KNN算法

  • 算法原理
  • 对数据的要求
  • 算法的优缺点
  • 算法需要注意的点
  • 算法实现(python)

算法原理

  1. 计算待测样本与train_data的距离d并保存数组中
  2. 对d进行排序,取d最近的k个样本
  3. 统计样本的类别或值(k个),取其类别最多的类别(或平均值)

对数据的要求

  1. 对于 缺失值需要处理(填充或者删除)
  2. 分类变量需要编码(涉及距离计算)
  3. 数据需要标准化或者归一化处理(消除量纲的影响。涉及距离计算的算法都需要考虑)

算法的优缺点

一、优点
1.准确度高,对异常值与噪声有较高的容忍度
2. 没有模型,无需参数估计与训练,容易理解与实现
3. 加入新模型不必重新训练
4. 适合处理多分类任务

一、缺点
1.计算复杂度高
2. 样本不均衡时预测偏差大
3. 可解释能力弱
4. 没有能力自动筛选指标
5. k值选取不确定(一般不超过20):

  • small(k) bias(小) variance(大)
  • large(k) bias(大) variance(小)

算法需要注意的点

1. 不平衡样本可以给KNN的预测造成哪些问题?有什么好的解决方式?
解决方法: 可能造成预测往分类类别较多的一方偏,造成预测有偏
改进方法: 1、设置样本权重,距离小的权重大,距离大的权重小;2、使用一定半径的点来取代距离最近的k个点(表现效果较好)
KD树(为了解决信息计算的冗杂度提高效率)(变量越多欧氏距离区分能力越差)    ⟹    \implies 在高维上效率低下(维度灾难)    ⟹    \implies Ball—Tree算法(优化KD树,耗时更长)

2. 为了解决KNN算法计算量过大的问题,可以使用分组的方式进行计算,简述一下该方式的原理?
将样本集按近邻关系分解成组,给出每组的质心位置,以质心为代表点和位置样本计算距离,选出距离最近的一个或若干个组,再在组内应用一般KNN算法,由于并不是将位置样本与所有样本计算距离,故该计算可减少计算量,但不能减少储存量

3. KD树建立过程中切分维度顺序是否可以优化?
可以先对每一个维度求方差,方差大说明数据越分散,则从方差大维度来逐步切分,可以获得更好的切分效果及树的平衡性

4. KD树每一次继续切分都要计算孩子区间在需切分维度上的中值,计算量很大有什么方法可以优化?
在构建KD树之前,依据每一维度先排序,在之后的切分中直接使用

算法实现(python)

import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.neighbors import KNeighborsClassifier 
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

import os
os.chdir(r'E:/wyz/Desktop/data/')
#读取数据
data = pd.read_excel('lw.xlsx',sheet_name = 'Sheet2')

#将类别数据转化为数字,就是一种人工打标签,具体的顺序可通过le.classes_查看(也可以用one_hot)
le = LabelEncoder()
str_variable = list(data.dtypes[data.dtypes.values == object].index)
for col in str_variable:    
    data[col] = le.fit_transform(data[col].astype(str))
####在单变量分析的基础上填充缺失值
data['var1'] = data['var1'].fillna(0.42089)
data['var2'] = data['var2'].fillna(125.854)
#划分数据集(3、7划分)
y = data_model['target']
x = data_model.drop('target', axis=1)
x_train, x_test, y_train, y_test = train_test_split(x, y,random_state=0,train_size=0.7)
#标准化数据(挑选做规则的变量最好不要标准化,建模时标准化)
ss_x = StandardScaler()
ss_y = StandardScaler()
x_train = ss_x.fit_transform(x_train)
x_test = ss_x.transform(x_test)

#训练
knn = KNeighborsClassifier() 
knn.fit(x_train, y_train)
#调用该对象的测试方法,主要接收一个参数:测试数据集
y_predict_test = knn.predict(x_test) 
#计算各测试样本基于概率的预测
probility_test=knn.predict_proba(x_test)  
#计算与最后一个测试样本距离在最近的5个点,返回的是这些样本的序号组成的数组
neighborpoint=knn.kneighbors([x_test[-1]],n_neighbors=5,return_distance=True)
#调用该对象的打分方法,计算出准确率
score=knn.score(x_test,y_test,sample_weight=None)

KNN参数详解

参数 默认值及输入类型 介绍
n_neighbors 默认值:5 int型参数,knn算法中指定以最近的几个最近邻样本具有投票权
weights 默认值:uniform str参数,即每个拥有投票权的样本是按什么比重投票,'uniform’表示等比重投票,'distance’表示按距离反比投票,[callable]表示自己定义的一个函数,这个函数接收一个距离数组,返回一个权值数组
algrithm 默认值:auto str参数即内部采用什么算法实现。有以下几种选择参数:‘ball_tree’:球树、‘kd_tree’:kd树、‘brute’:暴力搜索、‘auto’:自动根据数据的类型和结构选择合适的算法。默认情况下是‘auto’。暴力搜索就不用说了大家都知道。具体前两种树型数据结构哪种好视情况而定。KD树是对依次对K维坐标轴,以中值切分构造的树,每一个节点是一个超矩形,在维数小于20时效率最高–可以参看《统计学习方法》第二章。ball tree 是为了克服KD树高维失效而发明的,其构造过程是以质心C和半径r分割样本空间,每一个节点是一个超球体。一般低维数据用kd_tree速度快,用ball_tree相对较慢。超过20维之后的高维数据用kd_tree效果反而不佳,而ball_tree效果要好,具体构造过程及优劣势的理论大家有兴趣可以去具体学习
leaf_size 默认值:30 int参数基于以上介绍的算法,此参数给出了kd_tree或者ball_tree叶节点规模,叶节点的不同规模会影响数的构造和搜索速度,同样会影响储树的内存的大小。具体最优规模是多少视情况而定
matric 默认值:minkowski str或者距离度量对象,即怎样度量距离。默认是闵氏距离,闵氏距离不是一种具体的距离度量方法,它可以说包括了其他距离度量方式,是其他距离度量的推广,具体各种距离度量只是参数p的取值不同或者是否去极限的不同情况,具体大家可以参考这里,讲的非常详细
p 输入:2 int参数就是以上闵氏距离各种不同的距离参数,默认为2,即欧氏距离。p=1代表曼哈顿距离等等
metric_params 默认值:None 距离度量函数的额外关键字参数,一般不用管,默认为None
n_jobs 默认值:1 int参数,指并行计算的线程数量,默认为1表示一个线程,为-1的话表示为CPU的内核数,也可以指定为其他数量的线程,这里不是很追求速度的话不用管,需要用到的话去看看多线程。
函数 1、fit() 训练函数,它是最主要的函数。接收参数只有1个,就是训练数据集,每一行是一个样本,每一列是一个属性。它返回对象本身,即只是修改对象内部属性,因此直接调用就可以了,后面用该对象的预测函数取预测自然及用到了这个训练的结果。其实该函数并不是KNeighborsClassifier这个类的方法,而是它的父类SupervisedIntegerMixin继承下来的方法。
2、predict() 预测函数,接收输入的数组类型测试样本,一般是二维数组,每一行是一个样本,每一列是一个属性返回数组类型的预测结果,如果每个样本只有一个输出,则输出为一个一维数组。如果每个样本的输出是多维的,则输出二维数组,每一行是一个样本,每一列是一维输出。
3、predict_prob() 基于概率的软判决,也是预测函数,只是并不是给出某一个样本的输出是哪一个值,而是给出该输出是各种可能值的概率各是多少接收参数和上面一样返回参数和上面类似,只是上面该是值的地方全部替换成概率,比如说输出结果又两种选择0或者1,上面的预测函数给出的是长为n的一维数组,代表各样本一次的输出是0还是1.而如果用概率预测函数的话,返回的是n*2的二维数组,每一行代表一个样本,每一行有两个数,分别是该样本输出为0的概率为多少,输出1的概率为多少。而各种可能的顺序是按字典顺序排列,比如先0后1,或者其他情况等等都是按字典顺序排列。
4、score() 计算准确率的函数,接受参数有3个。 X:接收输入的数组类型测试样本,一般是二维数组,每一行是一个样本,每一列是一个属性。y:X这些预测样本的真实标签,一维数组或者二维数组。sample_weight=None,是一个和X第一位一样长的各样本对准确率影响的权重,一般默认为None.输出为一个float型数,表示准确率。内部计算是按照predict()函数计算的结果记性计算的。其实该函数并不是KNeighborsClassifier这个类的方法,而是它的父类KNeighborsMixin继承下来的方法。
5、kneighbors() 计算某些测试样本的最近的几个近邻训练样本。接收3个参数。X=None:需要寻找最近邻的目标样本。n_neighbors=None,表示需要寻找目标样本最近的几个最近邻样本,默认为None,需要调用时给出。return_distance=True:是否需要同时返回具体的距离值。返回最近邻的样本在训练样本中的序号。其实该函数并不是KNeighborsClassifier这个类的方法,而是它的父类KNeighborsMixin

你可能感兴趣的:(机器学习算法(分类))