机器学习十大经典算法之K-近邻算法(学习笔记整理)

一、算法概述

K-近邻算法(k-Nearest Neighbor,KNN)是机器学习算法中最简单最容易理解的算法。该算法的思路是:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例, 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。一般K不大于20。

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

二、 距离

  1. 欧式距离(Euclidean Distance)
    d ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 d(x,y) = \sqrt{\sum_{i=1}^{n} {(x_i-y_i)^2}} d(x,y)=i=1n(xiyi)2
  2. 曼哈顿距离(Manhattan Distance)
    d ( x , y ) = ∑ i = 1 n ∣ x i − y i ∣ d(x,y) = \sum_{i=1}^{n} {|x_i-y_i|} d(x,y)=i=1nxiyi
  3. 余弦距离(Cosine Distance)
    cos ⁡ ( θ ) = x ⃗ ⋅ y ⃗ ∣ ∣ x ∣ ∣ ⋅ ∣ ∣ y ∣ ∣ \cos(\theta)=\frac {\vec{x}\cdot\vec{y}} {||x||\cdot||y||} cos(θ)=xyx y
  4. 杰卡德距离(Jaccard Distance)
    J ( A , B ) = ∣ A ⋂ B ∣ ∣ A ⋃ B ∣ J(A,B)=\frac {|A\bigcap B|} {|A\bigcup B|} J(A,B)=ABAB

三、搜索近邻点的方法

1.暴力搜寻

计算所有已知样本与未知样本的距离,选出最近的K个样本进行投票。

2.KD树

构造KD树:
(1)计算训练集每个变量的方差,将最大方差的变量x作根节点的字段选择。
(2)按变量x对训练集做升序排序,以变量x的中位数为分割点划分为两个子节点,分割点保留在根节点中。
(3)重复(1)、(2)直到满足停止生产的条件为止。
KD树搜寻:
(1)测试集的数据点从某一节点开始,与划分当前节点的变量数据进行比较判断流入哪一侧子节点,直到落入对应的叶节点中。
(2)以测试集的数据点为中心,以叶节点中训练集数据点的最近距离为半径构成球体(该最近距离的点为临时近邻点),如果球体与上一层的父节点构成的分割线相交,则需要从父节点的另一侧叶节点重新搜寻近邻点,如果比刚才的临时近邻点距离更近,则更新临时近邻点。
(3)重复(2)直到找到最终的近邻点。

3.球树

构造球树:
(1)以训练集中距离最远的两个数据点的中间位置为球心构造一个超球体,则该超球体是包含所有训练集样本点的最小球体。
(2)从超球体中寻找离圆心最远的点p1,再寻找离p1最远的点p2,分别以这两个点为球心通过距离计算构造两个最小的超球体,将剩余的点划分到这两个超球体中。
(3)重复(1)、(2)直到球体无法继续划分为止。
球树搜寻:
(1)从最大或者最小的超球体开始,寻找测试集数据点落入的超球体。
(2)计算测试集数据点到所在超球体中最近点的距离d,计算测试集数据点与所在超球体成对的另一个超球体球心的距离D。如果D<d+r(对应的另一个超球体的半径),则需要回到上一层父节点对应的超球体搜寻近邻点。
(3)重复(2)直到找到最终的近邻点。

暴力搜寻简单易懂,但只适合小样本。KD树和球树虽然增加了计算复杂度,但是能在数据量较大时避免全局搜寻,提高效率。

四、K值的选择

K值太小,则模型复杂度较高,容易发生过拟合;K值太大,则会使得分类结果趋向众数的类别,从而导致分类失败。实际运用中通常采用交叉验证法来来选取最优的K值。

五、代码实现

首先是要用到的几个函数的官方文档说明。
1.

sklearn.model_selection.train_test_split(*arrays, **options)
在这里插入图片描述

sklearn.model_selection.cross_val_score(estimator, X, y=None, groups=None, scoring=None, cv=’warn’, n_jobs=None, verbose=0, fit_params=None, pre_dispatch=‘2*n_jobs’, error_score=’raise-deprecating’)
在这里插入图片描述
在这里插入图片描述

(1)sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=None, **kwargs)
(2)sklearn.neighbors.KNeighborsRegressor(n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=None, **kwargs)
在这里插入图片描述

接下来是代码。

1.分类

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import neighbors
from sklearn import metrics

data=pd.read_excel(r'C:\Users\sc\Desktop\data.xlsx')
#拆分为训练集和测试集
predictors=['pre1','pre2','pre3','pre4','pre5']
classification=['class']
x_train,x_test,y_train,y_test=model_selection.train_test_split(data[predictors], data[classification],
                                                               test_size=0.25,random_state=1234)
#设置k值集合
K=np.arange(1,int(np.ceil(np.log2(data.shape[0]))))
#存储不同k值的平均准确率
accuracy=[]
for k in K:
    #使用10折交叉验证的方法,比对每一k值下KNN模型的预测准确率
    cv_result=model_selection.cross_val_score(neighbors.KNeighborsClassifier(n_neighbors=k,
weights='distance'),x_train,y_train,cv=10,scoring='accuracy')
    accuracy.append(cv_result.mean())

#查询最大平均准确率的下标
arg_max=np.array(accuracy).argmax()
#绘制折线图
plt.rcParams['font.sans-serif']=['Microsoft YaHei'] #中文和负号正常显示
plt.rcParams['axes.unicode_minus']=False
plt.plot(K,accuracy) #折线图
plt.scatter(K,accuracy) #散点图
plt.text(K[arg_max],accuracy[arg_max],'最佳k值为%s' % int(K[arg_max]))
plt.show() #显示图形

#以最佳K值构建模型
knn_class=neighbors.KNeighborsClassifier(n_neighbors=int(K[arg_max]),weights='distance')
knn_class.fit(x_train,y_train)
predict=knn_class.predict(x_test)

#模型评估
print('Confusion Matrix:\n',pd.crosstab(y_test,predict)) #构建混淆矩阵
print('Overall Accuracy:',metrics.scorer.accuracy_score(y_test,predict)) #整体准确率
print('Assessment Report:\n',metrics.classification_report(y_test,predict)) #模型评估报告

在这里插入图片描述
在这里插入图片描述
从混淆矩阵来看,主要还是集中在主对角线,说明预测正确的占多数;而整体预测准确率为91%;从模型评估报告来看,第一列表示预测精度(预测正确的类别个数/该类别预测的所有个数),第二列表示预测覆盖率(预测正确的类别个数/该类别实际的所有个数),第三列是前两列的加权结果,第四列是类别实际的样本个数。

2.预测

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import model_selection
from sklearn import neighbors
from sklearn import metrics
from sklearn.preprocessing import minmax_scale

data=pd.read_excel(r'C:\Users\sc\Desktop\data.xlsx')
#数据归一化,消除量纲影响
predictors=data.columns[:-1]
X=minmax_scale(data[predictors])
#拆分为训练集和测试集
x_train,x_test,y_train,y_test=model_selection.train_test_split(X, data.classify,
                                                               test_size=0.25,random_state=1234)

#设置k值集合
K=np.arange(1,int(np.ceil(np.log2(data.shape[0]))))
#存储不同k值的平均MSE
mse=[]
for k in K:
    #使用10折交叉验证的方法,比对每一k值下KNN模型的MSE
    cv_result=model_selection.cross_val_score(neighbors.KNeighborsRegressor(n_neighbors=k,
weights='distance'),x_train,y_train,cv=10,scoring='neg_mean_squared_error')
    mse.append((-1*cv_result).mean()) #将负数转换为正数
#查询最小均方误差的下标
arg_min=np.array(mse).argmin()

#绘制折线图
plt.rcParams['font.sans-serif']=['Microsoft YaHei'] #中文和负号正常显示
plt.rcParams['axes.unicode_minus']=False
plt.plot(K,mse) #折线图
plt.scatter(K,mse) #散点图
plt.text(K[arg_min],mse[arg_min],'最佳k值为%s' % int(K[arg_min]))
plt.show() #显示图形

#以最佳K值构建模型
knn_reg=neighbors.KNeighborsRegressor(n_neighbors=int(K[arg_min]),weights='distance')
knn_reg.fit(x_train,y_train)
predict=knn_reg.predict(x_test)

#模型评估
print('MSE:',metrics.mean_squared_error(y_test,predict)) #均方误差越小越好

参考文献:
[1]scikit-learn官方文档:http://scikit-learn.org/stable/index.html
[2]Peter Harrington.《机器学习实战》.人民邮电出版社,2013-6
[3]刘顺祥.《从零开始学Python数据分析与挖掘》.清华大学出版社,2018

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值