01. 机器学习笔记01——K近邻算法 , CV_example
K近邻算法(K-nearest neighbor,KNN算法)
- 李航博士《统计学习方法》
- 最近邻(k-Nearest Neighbors,KNN)算法是一种分类算法
- 应用场景:字符识别、文本分类、图像识别
- 思想:对给定的训练实例点和输入实例点,首先确定输入实例点的k个最近邻训练实例点,然后利用这k个训练实例点的类的多数来预测输入实例点的类。
- 实现流程:
- (1)计算已知类别数据集(训练集)中的点与当前点的距离
- (2)按距离递增次序排序
- (3)选取与当前距离最小的k个点
- (4)统计前k个点所在的类别出现的频率
- (5)返回前k个点出现频率最高的类别作为当前点的预测分类
import sklearn
一、K-近邻算法API
- sklearn.neighbors.KNeighborsClassifier(n_neighbor=5)
- n_neighbors: int,可选(默认5),k_neighbors查询默认使用的邻居数
案例
- 1.获取数据集
- 2.数据基本处理(略)
- 3.特征工程(略)
- 4.机器学习
- 5.模型评估(略)
#全部行都能输出
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = 'all'
- 导入模块
from sklearn.neighbors import KNeighborsClassifier
- 构造数据集 / 获取数据
x=[[0],[1],[2],[3]] # 2维
y = [0,0,1,1]
- 机器学习 – 模型训练
# 实例化API
estimator = KNeighborsClassifier(n_neighbors=2)
# 使用fit方法进行训练
estimator.fit(x,y)
KNeighborsClassifier(n_neighbors=2)
# 预测
estimator.predict([[1]])
estimator.predict([[100]])
estimator.predict([[-1]])
array([0])
array([1])
array([0])
小结
k-近邻算法api初步使用
1.sklearn
优势:
1.文档多,且规范
2.包含算法多
3.实现起来容易
2.sklearn中包含内容
分类、回归、聚类
特征工程
模型选择、调优
3.KNN中的api
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
参数:
n_neighbors -- 选定参考几个邻居
4.机器学习中实现的过程
1.实例化一个估计器
2.使用fit方法进行训练
问题
- 除了欧氏距离,还可以使用什么距离?
- 选取k值的大小?
- API中其他参数的具体含义?
距离度量
1. 欧氏距离
2. 曼哈顿距离(城市街区距离)
3. 切比雪夫距离
4. 闵可夫斯基距离(Minkowski Distance) Lp范数
5. 标准化欧氏距离:在计算过程中加入标准差,对量刚数据进行处理
6. 余弦距离:cos思想
7. 汉明距离(Hamming Distance)
两个等长字符串s1与s2的汉明距离为:将其中一个变为另外一个所需要作的最小字符替换次数
8. 杰卡德距离: 通过交并集进行统计
9. 马氏距离:通过样本分布进行计算
K值选择 [***]
k值过小
容易受到异常点的影响
k值过大
受到样本均衡的问题
-
近似误差 – 过拟合 – 在训练集上表现好,测试集表现不好
-
估计误差好才是真的好
kd树
- 构造kd树
- 搜索kd树
二、 案例:鸢尾花种类预测 [****]
- 特征值4个:花瓣、花萼长度、宽度
- 目标值3个:setosa, vericolor, virginica
2.1 scikit-learn数据集API介绍
- 获取数据集
sklearn.datasets
小数据集:
sklearn.datasets.load_* ()
注意:该数据从本地获取
大数据集:
sklearn.datasets.fetch_* (data_home=None,subset=‘train’)
注意:该数据集从网上下载,subset表示获取的数据集类型
sklearn小数据集
- sklearn.datasets.load_iris()
- 加载并返回鸢尾花数据集
sklearn大数据集
- sklearn.datasets.fetch_20newsgroups(data_home=None,subset=‘train’)
- subset:‘train’或’test’,‘all’,可选,选择要加载的数据集
2.1 获取数据集
# 导入数据
from sklearn.datasets import load_iris,fetch_20newsgroups
# 1. 数据集获取
# 1.1 小数据集获取
iris = load_iris()
print(iris)
# 1.2 大数据集获取
# news = fetch_20newsgroups()
# print(news)
2.2 数据集返回值介绍(属性描述)
- 返回值类型是bunch – 字典
- 返回值的属性:
data:特征数据数组
target: 标签(目标)数组
DESCR: 数据描述
feature_names: 特证名
target_names: 标签(目标)名
print('数据集中的特征值是:\n',iris.data)
print('数据集中的目标值是:\n',iris['target'])
print('数据集中的特征值名字是:\n',iris.feature_names)
print('数据集中的目标值名字是:\n',iris.target_names)
print('数据集的描述:\n',iris.DESCR)
### 2.3 数据可视化
- 创建一些图进行可视化,以查看不同类别是如何通过特征来区分的
- Seaborn:画图更加美观舒适
- 安装:pip install seaborn
- seaborn.lmplot()-- 是一种非常有用的方法,在绘制二维散点图时可以自动完成拟合
- sns.lmplot(x,y,data,hue= ,fit_reg= ) -- 里的x,y代表横纵坐标的列名
- data= -- 具体数据集
- hue=* -- 目标值是什么,即代表按照species即花的类别分类显示
- fit_reg= -- 是否进行线性拟合
```python
%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
# 把数据转换成dataframe的格式
iris_d = pd.DataFrame(data=iris.data, columns=['sepal length', 'sepal width', 'petal length', 'petal width'])
iris_d['Species']= iris.target
# print(iris_d)
sepal length sepal width petal length petal width Species
0 5.1 3.5 1.4 0.2 0
1 4.9 3.0 1.4 0.2 0
2 4.7 3.2 1.3 0.2 0
3 4.6 3.1 1.5 0.2 0
4 5.0 3.6 1.4 0.2 0
.. ... ... ... ... ...
145 6.7 3.0 5.2 2.3 2
146 6.3 2.5 5.0 1.9 2
147 6.5 3.0 5.2 2.0 2
148 6.2 3.4 5.4 2.3 2
149 5.9 3.0 5.1 1.8 2
[150 rows x 5 columns]
def plot_iris(data,col1,col2):
sns.lmplot(x=col1,y=col2,data=data)
plt.show()
plot_iris(iris_d,'sepal length','sepal width')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1y1ksBFZ-1665913904350)(output_39_0.png)]
def plot_iris(data,col1,col2):
sns.lmplot(x=col1,y=col2,data=data,hue='Species') # 按Species类别分
plt.show()
plot_iris(iris_d,'sepal length','sepal width')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMobPddo-1665913904352)(output_40_0.png)]
def plot_iris(data,col1,col2):
sns.lmplot(x=col1,y=col2,data=data,hue='Species',fit_reg=False) # 不需要拟合曲线
plt.title('iris')
plt.xlabel(col1)
plt.ylabel(col2)
plt.show
plot_iris(iris_d,'sepal length','sepal width')
plot_iris(iris_d, 'sepal width', 'petal length') # 可以有6种组合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NmkZTyVD-1665913904353)(output_41_0.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GtnnoIAn-1665913904354)(output_41_1.png)]
2.4 数据集划分
- 训练数据:构建模型
- 测试数据:模型检验时,用于评估模型是否有效
数据集划分API
-
sklearn.model_selection.train_test_split(arrays,*options)
- x – 数据集的特征值
- y – 数据集的标签值
- test_size – 测试集的大小,一般为float
- random_state – 随机数种子,不同的种子会造成不同的随机采样结果,相同的种子采样结果相同
- return – 训练集特征值,测试集特征值,训练标签,测试标签(默认随机取)
-
from sklearn.model_selection import train_test_split
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(iris_d, iris.target)
print('训练集的特征值是:\n',x_train)
print('测试集的特征值是:\n',x_test)
print('训练集的目标值是:\n',y_train)
print('测试集的目标值是:\n',y_test)
训练集的特征值是:
sepal length sepal width petal length petal width Species
104 6.5 3.0 5.8 2.2 2
103 6.3 2.9 5.6 1.8 2
131 7.9 3.8 6.4 2.0 2
36 5.5 3.5 1.3 0.2 0
110 6.5 3.2 5.1 2.0 2
.. ... ... ... ... ...
108 6.7 2.5 5.8 1.8 2
24 4.8 3.4 1.9 0.2 0
142 5.8 2.7 5.1 1.9 2
76 6.8 2.8 4.8 1.4 1
85 6.0 3.4 4.5 1.6 1
[112 rows x 5 columns]
测试集的特征值是:
sepal length sepal width petal length petal width Species
16 5.4 3.9 1.3 0.4 0
128 6.4 2.8 5.6 2.1 2
129 7.2 3.0 5.8 1.6 2
139 6.9 3.1 5.4 2.1 2
2 4.7 3.2 1.3 0.2 0
125 7.2 3.2 6.0 1.8 2
94 5.6 2.7 4.2 1.3 1
82 5.8 2.7 3.9 1.2 1
58 6.6 2.9 4.6 1.3 1
45 4.8 3.0 1.4 0.3 0
22 4.6 3.6 1.0 0.2 0
44 5.1 3.8 1.9 0.4 0
113 5.7 2.5 5.0 2.0 2
3 4.6 3.1 1.5 0.2 0
34 4.9 3.1 1.5 0.2 0
116 6.5 3.0 5.5 1.8 2
81 5.5 2.4 3.7 1.0 1
65 6.7 3.1 4.4 1.4 1
35 5.0 3.2 1.2 0.2 0
31 5.4 3.4 1.5 0.4 0
54 6.5 2.8 4.6 1.5 1
124 6.7 3.3 5.7 2.1 2
93 5.0 2.3 3.3 1.0 1
145 6.7 3.0 5.2 2.3 2
14 5.8 4.0 1.2 0.2 0
96 5.7 2.9 4.2 1.3 1
37 4.9 3.6 1.4 0.1 0
92 5.8 2.6 4.0 1.2 1
63 6.1 2.9 4.7 1.4 1
17 5.1 3.5 1.4 0.3 0
146 6.3 2.5 5.0 1.9 2
114 5.8 2.8 5.1 2.4 2
71 6.1 2.8 4.0 1.3 1
23 5.1 3.3 1.7 0.5 0
50 7.0 3.2 4.7 1.4 1
39 5.1 3.4 1.5 0.2 0
148 6.2 3.4 5.4 2.3 2
78 6.0 2.9 4.5 1.5 1
训练集的目标值是:
[2 2 2 0 2 2 1 1 2 0 2 1 0 2 1 1 1 2 0 1 0 1 1 0 1 2 1 1 0 1 2 1 0 1 2 1 1
2 0 0 0 0 2 0 1 2 2 2 0 0 0 0 0 1 2 1 1 2 2 2 2 0 2 2 0 2 0 0 2 1 2 2 2 0
1 0 0 0 2 1 2 1 2 1 0 2 0 0 1 0 1 2 1 1 0 1 1 2 0 0 1 1 0 2 1 2 0 2 0 2 1
1]
测试集的目标值是:
[0 2 2 2 0 2 1 1 1 0 0 0 2 0 0 2 1 1 0 0 1 2 1 2 0 1 0 1 1 0 2 2 1 0 1 0 2
1]
print('训练集的目标值形状:\n',y_train.shape)
print('测试集的目标值形状:\n',y_test.shape) # 112:38,如果想改变训练集和测试机比重
训练集的目标值形状:
(112,)
测试集的目标值形状:
(38,)
x_train, x_test, y_train, y_test = train_test_split(iris_d, iris.target, test_size=0.5)
print('训练集的特征值是:\n',x_train)
print('测试集的特征值是:\n',x_test)
print('训练集的目标值形状:\n',y_train.shape)
print('测试集的目标值形状:\n',y_test.shape) # 75:75
训练集的目标值形状:
(75,)
测试集的目标值形状:
(75,)
# 随机数种子一样时,结果一样
x_train1, x_test1, y_train1, y_test1 = train_test_split(iris_d, iris.target, test_size=0.2,random_state=2)
x_train2, x_test2, y_train2, y_test2 = train_test_split(iris_d, iris.target, test_size=0.2,random_state=22)
x_train3, x_test3, y_train3, y_test3 = train_test_split(iris_d, iris.target, test_size=0.2,random_state=22)
print('测试集的目标值是:\n',y_test1)
print('测试集的目标值是:\n',y_test2)
print('测试集的目标值是:\n',y_test3)
测试集的目标值是:
[0 0 2 0 0 2 0 2 2 0 0 0 0 0 1 1 0 1 2 1 1 1 2 1 1 0 0 2 0 2]
测试集的目标值是:
[0 2 1 2 1 1 1 2 1 0 2 1 2 2 0 2 1 1 2 1 0 2 0 1 2 0 2 2 2 2]
测试集的目标值是:
[0 2 1 2 1 1 1 2 1 0 2 1 2 2 0 2 1 1 2 1 0 2 0 1 2 0 2 2 2 2]
三、特征工程:特征预处理 / 特征缩放[****]
定义
通过一些转换函数将特征数据转换成更加适合算法模型的特征数据过程:归一化、标准化
- 当不同特征的特征值数据范围相差很大时
包含内容
- 归一化
- 标准化
特征预处理API
sklearn.preprocessing
1. 归一化
定义
通过对原始数据进行变换把数据映射到【0,1】之间
公式
x’=(x-min) / (max-min)
API
- sklearn.preprocessing.MinMaxScaler(
feature_range=(0,1)…) - MinMaxScalar.fit_tranfrom(X)
- 参数:
- X: numpy array格式的数据[n_samples, n_features]
- 返回值:转化后的形状相同
- 参数:
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
# data = pd.read_csv('./data/dating.txt')
print(data)
# 1.归一化
# 1.1实例化一个转化器
transfer =MinMaxScaler(feature_range=(0,10))
# 1.2调用fit_transfrom方法
minmax_data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
print('经过归一化数据处理之后的数据为:\n',minmax_data)
归一化总结
- 注意最大值和最小值是变化的,非常容易受到异常值点的影响,所以这种方法鲁棒性较差(稳定性较差)
- 只适合传统精确小数据情形(以后不用你了)
2. 标准化
定义
通过对原始数据进行数据变换到均值为0,标准差为1范围内
公式
X'= (x-mean) / σ
- 对于归一化:如果出现异常点,影响了最大值最小值,那么结果显然会发生改变
- 对于标准化:如果出现异常值点,由于具有一定数据量,少量的异常值点对于平均值的影响不大,从而方差该表较小
API:
- sklearn.preprocessing.StandardScaler()
- 处理之后每列来说所有数据都聚集在均值为0附近,标准差为1
- StandardScaler.fit_transform(X)
X:numpy array数据[n_samples,n_features]
- 返回值:转换后的形状相同的array
from sklearn.preprocessing import StandardScaler
# 2.标准化
# 2.1实例化一个转换器
transfer = StandardScaler()
# 2.2调用fit_transfrom方法
standard_data = transfer.fit_transform(data[['milage','Liters','Consumtime']])
print('经过标准化处理之后的数据为:\n',standard_data)
标准化总结
- 异常值对我影响小
- 适合现代嘈杂大数据情形(以后就是用你了)
四、案例:鸢尾花种类预测-流程实现
-
sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm=‘auto’)
- algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’}
- auto:算法自己决定合适的搜索算法
- kd_tree:维数小于20时效率高,超平面
- ball_tree:维数大于20时使用,超球体
- algorithm:{‘auto’,‘ball_tree’,‘kd_tree’,‘brute’}
-
1.获取数据集
-
2.数据基本处理
-
3.特征工程
-
4.机器学习
-
5.模型评估
导入模块
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
1. 获取数据集
iris = load_iris()
2. 数据基本处理
# 数据异常值处理(这里数据收集的比较好,省略)
# 2.1 数据分割
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22, test_size=0.2)
3. 特征工程
# 3.1 实例化一个转换器
transfer = StandardScaler()
# 3.2 调用fit_transform方法
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)
4.机器学习(模型训练)
# 4.1 实例化一个估计器
estimator = KNeighborsClassifier(n_neighbors=5)
# 4.2 模型训练
estimator.fit(x_train, y_train)
KNeighborsClassifier()
5.模型评估
# 5.1 输出预测值
y_pre = estimator.predict(x_test)
print('测试集的预测值是:\n',y_pre)
print('预测值和真实值对比:\n',y_pre == y_test)
测试集的预测值是:
[0 2 1 1 1 1 1 1 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 1 0 1 1 2 1]
预测值和真实值对比:
[ True True True False True True True False True True True True
True True True True True True False True True True True True
False True False False True False]
# 5.2 输出准确率
ret = estimator.score(x_test,y_test)
print('准确率是:\n',ret)
准确率是:
0.7666666666666667
五、K近邻算法总结
优点
- 简单有效
- 重新训练的代价低
- 适合类域较差样本
- 适合大样本自动分类
缺点
- 惰性学习
- 类别评分不是规格化
- 不像一些概率评分的分类
- 输出可解释性不强
- 对不均衡的样本不擅长
- 样本不均衡:收集到的数据每个类别占比严重失衡
- 计算量较大
六、交叉验证,网格搜索
- 4.1 实例化一个估计器
- estimator = KNeighborsClassifier(n_neighbors=5)
- 4.2 模型训练
- estimator.fit(x_train, y_train)
此时如何确定n_neighbors的具体值
1、交叉验证
- 将拿到的训练集分为训练集和验证集
- 我们之前将数据分为训练集和测试集,但是为了让从训练得到的模型结果更加准确,将拿到的训练数据分为训练集和验证集。
- 训练集:训练集+验证集(验证模型怎么样,如准确率)
- 测试集:测试集
- 4折交叉验证:将训练集分为四份,依次将其中一份做为验证集,一共经过4次(组)的测试,每次更换不同的验证集,即得到4组模型的结果,取平均值作为最终结果(测试得到的准确率)。
为什么需要交叉验证?
- 交叉验证目的:为了让被评估的模型更加准确可信
- 不能提高模型的准确率,只是让模型输出的准确率更加可信。
问题:那么这个只是对于参数得出更好的结果,那么怎么选择或者调优参数呢?
2、什么是网格搜索
通常情况下,有很多参数时需要手动指定的(如K-邻近算法中的K值),这种叫超参数。但是手动过程繁杂,所以需要对模型预设几种超参数组合。
每组超参数都采用交叉验证来进行评估,最后选出最优参数组合模型
- 例如:K值可能取{3,5,7},使用4折交叉验证,那么当K=3时训练4次,K=5时训练4次,K=7时训练4次,一共训练12次。
超参数:sklearn中需要手动指定的参数叫做超参数
网格搜索:就是把这些超参数的值,通过字典的形式传递进去,然后进行选择最优值。
3、交叉验证,网格搜索(模型选择和调优)API:
- sklearn.model_selection.GridSearchCV(estimator,param_grid=None,cv=None)
- 对估计器的指定参数进行详尽搜索
- estimator:估计器对象,用哪个训练模型\估计器来进行交叉验证、网格搜索
- param_grid:估计器参数(dict) 例:{‘n_neighbors’:[1,3,5]}
- cv: 指定几折交叉验证
- fit:输入训练数据集
- score:准确率
- 结果分析
- best_score_:在交叉验证中验证的最好结果
- best_estimator_:做好的参数模型
- cv_results_:每次交叉验证后的验证集准确率结果和训练集准确率结果。
4.鸢尾花案例增加K值调优
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris()
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.2)
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.fit_transform(x_test)
estimator = KNeighborsClassifier(n_neighbors = 1)
# 调用交叉验证网格搜索模型
param_grid={'n_neighbors':[1,3,5]}
estimator = GridSearchCV(estimator,param_grid=param_grid,cv=10,n_jobs=-1)
estimator.fit(x_train,y_train)
GridSearchCV(cv=10, estimator=KNeighborsClassifier(n_neighbors=1), n_jobs=-1,
param_grid={'n_neighbors': [1, 3, 5]})
y_pre = estimator.predict(x_test)
print('预测值是:\n',y_pre)
print('预测值和真实值对比:\n',y_pre == y_test)
预测值是:
[0 2 2 2 1 0 0 1 2 0 0 0 2 1 2 2 1 2 2 2 0 1 2 0 0 1 0 0 1 0]
预测值和真实值对比:
[ True True True False True True True True True True True True
True True True True True True True True True True True True
True True True True True True]
ret = estimator.score(x_test,y_test)
print('准确率是:\n',ret)
准确率是:
0.9666666666666667
# 其他评价指标
print('最好的模型:\n',estimator.best_estimator_)
print('最好的结果:\n',estimator.best_score_)
print('整体的模型结果:\n',estimator.cv_results_)
最好的模型:
KNeighborsClassifier()
最好的结果:
0.9333333333333332
整体的模型结果:
{'mean_fit_time': array([0.00119724, 0.00099754, 0.00089726]), 'std_fit_time': array([3.99462801e-04, 1.78416128e-06, 2.99092610e-04]), 'mean_score_time': array([0.00189519, 0.00179517, 0.0013967 ]), 'std_score_time': array([0.00053735, 0.00059831, 0.00048877]), 'param_n_neighbors': masked_array(data=[1, 3, 5],
mask=[False, False, False],
fill_value='?',
dtype=object), 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}], 'split0_test_score': array([0.91666667, 0.91666667, 0.91666667]), 'split1_test_score': array([1., 1., 1.]), 'split2_test_score': array([0.66666667, 0.58333333, 0.66666667]), 'split3_test_score': array([0.91666667, 0.91666667, 0.91666667]), 'split4_test_score': array([0.91666667, 1. , 1. ]), 'split5_test_score': array([0.91666667, 0.91666667, 0.91666667]), 'split6_test_score': array([0.91666667, 1. , 1. ]), 'split7_test_score': array([1., 1., 1.]), 'split8_test_score': array([0.91666667, 0.91666667, 0.91666667]), 'split9_test_score': array([0.91666667, 1. , 1. ]), 'mean_test_score': array([0.90833333, 0.925 , 0.93333333]), 'std_test_score': array([0.08700255, 0.1204736 , 0.09718253]), 'rank_test_score': array([3, 2, 1])}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)