#KNN

本文github 代码:https://github.com/crystal30/KNN

#KNN_第1张图片

一.  # KNN algorithm 原理

KNN:k-nearest neighbors algorithm,

(1)用途:分类,且天然的可以解决多分类问题(sklearn.neighbors.KNeighborsClassifier)

          回归(sklearn.neighbors.KNeighborsRegressor)

(2)优点:实现简单,易于理解

(3)缺点:

效率低下:训练集共有m个样本,每个样本有n个特征,则预测每一个新的数据需要O(m*n)

                优化:使用树的结构:KD-Tree,Ball-Tree

高度数据相关:

预测的结果不具有可解释性,其只是根据距离来判断

维数灾难:

#KNN_第2张图片

解决方法:降维(后续后涉及)。

1分类的原理:

1.1

#KNN_第3张图片

如上图所示:

场景描述:数据有红、蓝两类,此时进来一个新的数据(绿色表示),用KNN算法来预测绿色属于哪一类,其中K=3

假设:上图的点的坐标都是已知的,

算法步骤:(1)计算绿点到各个点(所有黄点和蓝点,我们也称为训练数据)的距离(一般使用欧式距离)

                (2)K=3,根据距离得到离绿点最近的3个点

                (3)统计这三个点中,哪一类的数据最多,则绿点就属于哪一类(如上图,离绿点最近的三个点中,有两个是红点,一个点是蓝点,则可以判定绿点属于红色的那一类)

1.2 利用 sklearn datasets中鸢尾花的数据集  KNN的简单的实现

import numpy as np

 

import matplotlib.pyplot as plt
from sklearn import datasets
import math

 

from collections import Counter

iris = datasets.load_iris()   #加载鸢尾花的数据到 iris中
iris.keys()
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])

 

Row_ind = np.arange(0,100,10)  #array([ 0, 10, 20, 30, 40, 50, 60, 70, 80,90])
#为简单起见,我们从第一类和第二类鸢尾花中各取出5个数据
X_train = iris.data[Row_ind,2:]
y_train = iris.target[Row_ind]
#绘图
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color = 'r')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color = 'b')
plt.show()
#KNN_第4张图片

 

new = iris.data[56,2:] #新进入一个点,预测这个点属于哪一类
distances = np.array([math.sqrt(i) for i in np.sum((X_train -new)**2,axis=1)]) # 计算出new 到每个点的欧式距离

#distances 的输出:    array([3.58468967, 3.49284984,3.31058907, 3.40147027, 3.64005494,

                                                      0.2       , 1.34164079, 0.2236068 , 1.02956301,0.5       ])

nearest = distances.argsort() #将距离从小大大排序,取出arg

k=7 #取最临近的7个点
top_y = y_train[nearest[:k]]

 

votes = Counter(top_y) #统计top_y 中的数据

#votes输出:    Counter({0: 2, 1: 5})

 

 

 

predict_newy = votes.most_common(1)[0][0] #输出统计结果中最common的lable

 

 

二 KNN算法的封装

1.将上述的实现过程整理为一个函数  KNN(X_train,y_train,newx,k),并保存在KNN.py文件中,以便我们后续调用。

2.sklearn中KNeighborsClassifier 算法的使用

   一般,sklearn 中的机器学习算法,都是以面向对象的方式进行封装。以KNeighborsClassifier 为例子,均有以下几个步骤

  (1) 创建实例 knn_clf = KNeighborsClassifier(n_neighbors=7)

  (2) 拟合:knn_clf.fit(X_train,y_train)

  (3)预测:knn_clf.predict(new)

3.将我们编写的KNN算法也以面向对象的方式进行封装,即创建类:KNNClf, 并将其存放在KNNClf.py中

 具体的代码见github:https://github.com/crystal30/KNN

 

三. KNN根据算法的性能 设置超参数

#KNN_第5张图片

 

#KNN_第6张图片

#KNN_第7张图片

 

1.性能一般用Accuracy来测量:

(1)首先编写myTrain_test_split函数,将数据集分成 从训练集和测试集。
     当然,也可以直接调用 sklearn 中的函数
     from sklearn.model_selection import train_test_split

 

(2)假设:我们的测试数据为:X_test, 测试数据的标签为 y_test, 用算法预测的标签为y_predict

accuracy = 预测的正确的数量/总的测试样本数

用程序来写就是 accuracy = sum(y_predict == y_test)/len(y_test)

代码:test accuracy1.ipynb 以及代码的封装:  accaracy 封装_load digits2.ipynb

Q:在模型进入真实环境前,怎样改进模型呢? 

        可以通过设置合理的超参数 来是模型的测试误差最小

2.超参数:

超参数:即指 在运行机器学习算法之前需要指定的参数,KNN中的K即为典型的超参数。

调参:这里的“参”,一般指的就是超参数

(更优)超参数的寻找:领域知识

                                经验数值(算法中默认的值一般可认为是经验数值)

                                实验搜索

1.1KNN模型中超参数的设置

(1)KNN算法没有模型参数,KNN算法中的K是典型的超参数

 

根据

class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5weights=’uniform’algorithm=’auto’leaf_size=30p=2metric=’minkowski’metric_params=Nonen_jobs=1**kwargs)

我们初步的来设置n_neighbors(即KNN中的K),weights,p 这几个超参数

具体的每个参数的含义可查询document 

http://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier

[source]

(2)weights:考虑距离权重,即把每个点到要预测数据的距离的倒数作为权重。某个点距离预测点越近,则权重越大。

#KNN_第8张图片

 

#KNN_第9张图片

 

(3)p:距离算法的选择,上面我们一直用的是欧式距离,用曼哈顿距离,性能会不会更好呢?

欧式距离:#KNN_第10张图片,变形#KNN_第11张图片

 

曼哈顿距离:#KNN_第12张图片 ,        变形     #KNN_第13张图片

 

明可夫斯基距离:#KNN_第14张图片

这样我们对使用哪种距离的选择就变成了对超参数p的选择。

注意:欧式距离和曼哈顿距离都是明可夫斯基距离的一种,KNeighborsClassifier 中metric 默认的是’minkowski’。

KNeighborsClassifier(n_neighbors=5weights=’uniform’algorithm=’auto’leaf_size=30p=2metric=’minkowski’metric_params=Nonen_jobs=1**kwargs)

当然还有很多其他的距离,如

#KNN_第15张图片

在这里,我们不予考虑。

代码:search Hyper-parameter 3.ipynb

 

1.2 利用sklearn中的模块对KNN模型中超参数的选择——网格搜索

from sklearn.model_selection import GridSearchCV

详见github代码:Grid_Search_HyperParameters4

四.训练数据和测试数据的归一化

Q:为什么我们要对数据归一化呢?下面我们来做一个简单的示例。

原始数据:

#KNN_第16张图片

如上图所示:假设我们有两个样本,每个样本有两个特征:肿瘤大小和发现时间。

                    如果再来一个新的测试数据,计算其到样本1,样本2的距离,则特征肿瘤大小的贡献微乎其微,但特征肿瘤大小对                     判断是否是恶性肿瘤是一个很重要的因素,此时,就需要我们对数据归一化,即将肿瘤大小和发现时间归一化在同                     一个量级,而样本间同一个特征值的相对大小不变。

数据归一化后:

#KNN_第17张图片

这样再算测试数据到样本间距离时,将不由某一个特征的主导。

1.数据标准化的理论知识

数据归一化,即将所有的数据映射到同一尺度。如上实例所示,我们是将肿瘤大小和发现时间映射到了同一尺度。

1.1 将特征数据缩放到一个范围 scale to a range

使用这一方法的情况一般有两种:

  • 特征的标准差较小
  • 可以使稀疏数据集中的0值继续为0,特别适用于缩放稀疏数据。

(1)最值归一化(MinMaxScaler):把所有的数据映射到0-1之间。适用于分布有明显边界的情况(如:考试成绩)

#KNN_第18张图片

缺点:容易受边界极端值的影响。

(2) MaxAbsScaler,标准化后的数据的取值范围为[-1, 1]

#KNN_第19张图片

 

1.2 均值方差归一化(standardization)

把所有的数据归一到均值为0,方差为1的分布中。数据分布没有明显的边界,有可能存在极端数据值。

均值方差归一化,通常也称z-score标准化,即将数据转化成均值为0方差为1的高斯分布,但是对于不服从标准正态分布的特征,这样做效果会很差。

#KNN_第20张图片

1.3 RobustScaler

Scale features using statistics that are robust to outliers.

 

2. 标准化与归一化的区别

标准化是依照特征矩阵的列处理数据,比如通过求z-score的方法,将样本的特征值转换到同一量纲下。归一化是依照特征矩阵的行处理数据,其目的在于样本向量在点乘运算或其他核函数计算相似性时,拥有统一的标准,也就是说都转化为“单位向量”。常用于文本分类和内容聚类的向量空间模型。

规则为l2的归一化公式如下:


 


可使用sklearn.preprocessing库的Normalizer类对数据进行归一化。

3.数据归一化的简单程序实现

见github代码:data_X_train_Normalize5

4. 对sklearn.datasets 中的数据进行归一化

一般我们比较常用的是均值方差归一化,所以,我们我们这里仅讨论均值方差归一化的情况。

from sklearn.preprocessing import StandardScaler 实现数据归一化

from KNNProject.preprocessing import StandardScaler 实现数据归一化(KNNProject 为本地自己编写的包)

(1)一般,我们有训练数据集,和测试数据集,对这两个数据集都需要归一化。而我们往往不知道下一个测试数据会是什么,即测试数据我们不能完整的获得。

所以:

#KNN_第21张图片

#KNN_第22张图片

归一化的过程:

#KNN_第23张图片

 

github代码:skl_local_normalize6

标准化后与标准化之前的预测准确率相比,有明显的改进。

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(python,算法/ML)