目录
1、K临近算法
(1)K近邻算法的原理介绍
K近邻算法的原理非常简单:对于一个新的数据而言,K近邻算法的目的就是在已有数据中寻找与它最相似的K个数据,或者说“离它最近”的K个数据,如果这K个点大多数属于某一个类别,则该样本也属于这个类别。
以下图为例,假设五角星和三角形分别代表两类不同的电影,一类是爱情片,一类是动作片。此时加入一个新样本正方形,此时需要判断该电影的类别:选择离新样本最近的3个近邻点时(K=3)为判断依据时,这3个点由1个五角星和2个三角形组成,可以认为新样本属于三角形的类别,即新样本是一部动作片。选择离新样本最近的5个近邻点时(K=5)为判断依据时,5个点由3个五角星和2个三角形组成,可以认为新样本属于五角星的类别,即新样本是一部爱情片。
实际应用中,数据的特征通常有n个,此时可将该距离公式推广到n维空间,如n维向量空间下A点坐标为(A1,A2,A3,...An),B点坐标为(B1,B2,B3,...,Bn),那么A、B两点间的欧氏距离为:
(2)K近邻算法的计算步骤及代码实现
先用一个简单的数学案例讲解下kNN算法的步骤。这里以一个简单的例子来讲解一下K近邻算法的基本原理:如何判断葡萄酒的种类。为方便演示,我们只选取了2个特征变量来对葡萄酒进行分类,实际生活中,用来评判葡萄酒的指标要多得多。此处假设可以根据酒精含量和苹果酸含量将葡萄酒分为2类。
1、读取数据
import pandas as pd
df = pd.read_excel('葡萄酒.xlsx')
df
此时的df如下表所示,为方便演示,该数据集只有5个原始样本数据
现在需要使用K近邻算法对一个新样本进行分类,该新样本的特征数据如下所示,那么这个新样本是属于葡萄酒A呢,还是属于葡萄酒B呢?
2、计算距离
此时我们可以利用距离公式来计算新样本与已有样本之间的距离,也即不同样本间的相似度,例如我们可以计算新样本与样本1的距离,公式如下:
同理可以计算新样本与其他原始样本的距离,如下表所示:
3、根据K值判定类别
获得了各个原始样本与新样本的距离后,我们就可以将其根据距离由近到远进行排序,如下表所示:
如果令K值等于1,就是以离新样本距离最近的原始样本的种类作为新样本的种类,那么新样本离样本2最近,那么新样本的分类为0,也就是葡萄酒A。如果令K值等于3,就是以离新样本最近的3个原始样本的多数样本的种类为判断依据,此时最近的3个原始样本是样本2、样本1、样本4,它们中以分类0居多,所以判定新样本的分类为0,也就是葡萄酒A。
4、K近邻算法的代码实现
上面讲解了K近邻算法基本运算步骤,而其实这些运算步骤在Python中已经有相关的库给封装好了,直接进行调用即可。把原始数据进行特征变量和目标变量的切分从而方便之后进行模型的训练,代码如下:
X_train = df[['酒精含量(%)','苹果酸含量(%)']]
y_train = df['分类']
然后就可以直接调用Python已经开发好的相关库来进行K进邻算法的运算了,代码如下:
from sklearn.neighbors import KNeighborsClassifier as KNN
knn = KNN(n_neighbors=3)
knn.fit(X_train, y_train)
模型训练完之后就可以来进行预测了,代码如下:
X_test = [[7, 1]] # X_test为测试集特征变量
answer = knn.predict(X_test)
print(answer)
此时得到的预测结果answer为0,和之前通过数学运算的方法获得结果一致。
5、K近邻算法回归模型
K近邻算法除了可以做分类分析,也可以做回归分析,分别对应的模型为K近邻算法分类模型(KNeighborsClassifier)及K近邻算法回归模型(KNeighborsRegressor):
K近邻算法回归模型的引入方式:
from sklearn.neighbors import KNeighborsRegressor
K近邻算法回归模型简单代码演示如下所示:
from sklearn.neighbors import KNeighborsRegressor
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [1, 2, 3, 4, 5]
model = KNeighborsRegressor(n_neighbors=2)
model.fit(X, y)
print(model.predict([[5, 5]]))
2、数据预处理之数据归一化
这一节主要讲解一个数据预处理的一个技巧:数据归一化(也称数据标准化)。数据归一化的目的是为了消除不同特征变量量纲相差较大的影响。例如下表所示,我们把上节的酒精含量都放大10倍仅作教学演示,苹果酸含量保持不变,此时两者的量纲级别相差就较大了。
此时如果直接使用K近邻算法来进行建模,那么酒精含量在模型中的重要性将远远超过苹果酸的含量,这样会丧失苹果酸含量这一特征变量的作用,而且结果也会有较大误差。举例说明,对于一个新的样本,其酒精含量为70%,苹果酸含量为1%,此时它与样本1的距离公式为:
可以看到此时的距离几乎就是由酒精含量主导,苹果酸含量由于量纲相差较大,几乎不发挥作用,那么此时如果不进行数据数据预处理,会导致预测结果有失偏颇。
(1)min-max标准化
min-max标准化(Min-Max Normalization)也称离差标准化,它利用原始数据的最大最小值把原始数据转换到[0,1]区间内,转换函数如下:
在Python中可以直接调用min-max标准化的相关模块,代码如下:
import pandas as pd
df = pd.read_excel('葡萄酒2.xlsx')
X = df[['酒精含量(%)','苹果酸含量(%)']]
y = df['分类']
X_new = MinMaxScaler().fit_transform(X)
X_new
数据归一化后的特征变量X_new如下所示:
array([[0.16666667, 0.5 ],
[0.33333333, 0. ],
[0. , 0. ],
[0.66666667, 1. ],
[1. , 0.5 ]])
(2)Z-score标准化
Z-score标准化(mean normaliztion)也称均值归一化,通过原始数据的均值(mean)和标准差(standard deviation, std)对数据进行归一化。归一化后的数据符合标准正态分布,即均值为0,标准差为1。转化函数为
在Python中有现成的模块可以对数据进行均值归一化处理,代码如下:
from sklearn.preprocessing import StandardScaler
X_new = StandardScaler().fit_transform(X)
X_new
此时数据归一化后的特征变量X_new如下所示:
array([[-0.74278135, 0.26726124],
[-0.27854301, -1.06904497],
[-1.2070197 , -1.06904497],
[ 0.64993368, 1.60356745],
[ 1.57841037, 0.26726124]])
3、案例 - 手写数字识别模型
(1)背景
图像识别是机器学习领域一个非常重要的应用场景,像现在非常火的人脸识别就是基于机器学习的相关算法,这里首先介绍一个较为简单的图像识别的案例:手写数字识别模型,在之后的章节讲解完PCA主成分分析后,我们将再介绍人脸识别的代码实现,两者的原理其实都有共通之处,所以这里学完手写数字识别模型后,会对人脸识别也会有个初步的了解。
(2)手写数字识别原理
手写数字识别的本质就是把如下图所示的手写数字图片转换成计算机能够处理的数字。
1、图像二值化
如下图所示,我们将图片格式的数字4转换成由0和1组成的“新的数字4”了。这是一个32x32大小的矩阵,数字1代表有颜色的地方,数字0代表无颜色的地方,这样就完成了手写数字识别的最关键的第一步:将图片转为计算机能识别的内容:数字0和1,这个也叫作图像二值化。
为此,我们需要将任务分为3个部:
1.图像转换为32x32
第三方图像处理库Pillow库是Python一款功能强大的图像处理库,简单好用,使用人数众多,如果没有该库的话,可以通过“pip install pillow”进行安装,简单演示代码如下:
from PTL import Image
img=Image.open('数字4.png')
img=img.resize((32,32))
2.图片灰度处理
此时获得的是一个彩色的数字4,我们需要对其进行灰度处理,将其变成黑白颜色,方便之后好将其转换成数字0和1,代码如下:
img=img.convert('L')
3.图像二值化处理
获得黑白颜色的数字4后,下面就是关键的图像二值化处理了,代码如下:
import numpy as np
img_new = img.point(lambda x: 0 if x > 128 else 1)
arr = np.array(img_new)
此时可以直接将arr通过print()函数打印出来,不过因为其行列较多,可能显示不全,所以我们通过如下代码打印它的每一行,其中arr.shape反映的是数组的行数和列数,arr.shape[0]表示行数(arr.shape[1]则表示列数),这样通过for循环就可以打印每行内容了。
2、二维数组转换为一维数组
经过图像二值化的处理之后,我们获得了一个二维的数组(32x32的0-1矩阵),为了方便进行机器学习建模,还需要对这个二维数组进行一个简单处理:在上图二维数组中,第一行之后依次拼接第二行的32个数字,第三行的32个数字……直至第32行的32个数字,这时候便得到一个1x1024的一维数组,如下所示:
需要通过reshape(1, -1)方法将其转换成一行(若reshape(-1,1)则转为一列),也即1*1024的一维数组,代码如下:
arr_new = arr.reshape(1, -1)
arr_new
3、距离计算
因此我们可以利用K近邻算法模型计算新样本与原始训练集中各个样本的欧氏距离,取新样本的k个近邻点,并以大多数近邻点所在的类别作为新样本的分:
(3)手写数字识别编程实现
这里的数据集为1934个处理好的手写数字0-9的1x1024矩阵。如下图所示,其中每一行对应一个手写数字,第一列“对应数字”为对应的手写数字,其余每一列为该手写数字对应的1x1024矩阵中的每一个数字:
1、读取数据
首先通过pandas库读取数据,代码如下:
import pandas as pd
df = pd.read_excel('手写字体识别.xlsx')
df.head()
此时获取数据前5行如下所示:
2、提取特征变量和目标变量
通过如下代码将特征变量和目标变量单独提取出来,代码如下:
X = df.drop(columns='对应数字')
y = df['对应数字']
这里所有样本的1x1024矩阵元素都由0,1构成,所以不需要再归一化处理样本数据。如果在其他场景下中出现数量级相差较大的特征变量,便还需要对数据进行归一化处理。
3、划分训练集和测试集
通过和之前章节类似的代码划分训练集和测试集数据:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=123)
4、模型搭建
划分完训练集和测试集数据后,我们使用K近邻算法分类器进行模型搭建,代码如下:
from sklearn.neighbors import KNeighborsClassifier as KNN
knn = KNN(n_neighbors=5)
knn.fit(X_train, y_train)
5、预测数据结果
通过和之前章节类似的代码,我们可以将预测值和实际值进行对比:
y_pred = knn.predict(X_test)
print(y_pred[0:100])
将此时的a打印输出如下:
预测值 | 实际值 | |
0 | 5 | 5 |
1 | 3 | 3 |
2 | 7 | 7 |
3 | 8 | 8 |
4 | 9 | 9 |
通过如下代码可以查看所有测试集的预测准确度:
from sklearn.metrics import accuracy_score
score = accuracy_score(y_pred, y_test)
score
除了用accuracy_score()函数来获取模型评分外,其实Scikit-Learn库的K近邻分类器自带模型评分功能,代码如下:
score = knn.score(X_test, y_test)
如果想进行参数调优,如上面采取的参数n_neighbors为默认值5,如果想看换成别的数是否更优,可以模仿之前讲解决策树模型时候的交叉验证和网格搜索来进行参数调优,代码如下:
from sklearn.model_selection import GridSearchCV
parameters={'n_neighbors':[1,2,3,4,5,6,7,8]}
knn=KNN()
grid_search=GridSearchCV(knn,parameters,cv=5)
grid_search.fit(X_train,y_train)
grid_search.best_params_['n_neighbors']