KNN分类
复制代码
KNN算法介绍(K Nearest Neighbors), K近邻算法
原理:
基于 欧式距离(或者其它距离计算方式)计算 测试集 和 每个训练集之间的距离, 然后根据距离升序排列, 找到最近的K个样本.
基于K个样本投票, 票数多的就作为最终预测结果 -> 分类问题.
基于K个样本计算平均值, 作为最终预测结果 -> 回归问题.
实现思路:
1. 分类问题
适用于: 有特征, 有标签, 且标签是不连续的(离散的)
2. 回归问题.
适用于: 有特征, 有标签, 且标签是连续的.
KNN算法, 分类问题思路如下:
1. 计算测试集和每个训练的样本之间的 距离.
2. 基于距离进行升序排列.
3. 找到最近的K个样本.
4. K个样本进行投票.
5. 票数多的结果, 作为最终的预测结果.
代码实现思路:
1. 导包.
2. 准备数据集(测试集 和 训练集)
3. 创建(KNN 分类模型)模型对象.
4. 模型训练.
5. 模型预测.
python
复制代码
"""
KNN算法介绍(K Nearest Neighbors), K近邻算法
原理:
基于 欧式距离(或者其它距离计算方式)计算 测试集 和 每个训练集之间的距离, 然后根据距离升序排列, 找到最近的K个样本.
基于K个样本投票, 票数多的就作为最终预测结果 -> 分类问题.
基于K个样本计算平均值, 作为最终预测结果 -> 回归问题.
实现思路:
1. 分类问题
适用于: 有特征, 有标签, 且标签是不连续的(离散的)
2. 回归问题.
适用于: 有特征, 有标签, 且标签是连续的.
KNN算法, 分类问题思路如下:
1. 计算测试集和每个训练的样本之间的 距离.
2. 基于距离进行升序排列.
3. 找到最近的K个样本.
4. K个样本进行投票.
5. 票数多的结果, 作为最终的预测结果.
代码实现思路:
1. 导包.
2. 准备数据集(测试集 和 训练集)
3. 创建(KNN 分类模型)模型对象.
4. 模型训练.
5. 模型预测.
"""
# 1. 导包.
from sklearn.neighbors import KNeighborsClassifier # 分类
# from sklearn.neighbors import KNeighborsRegressor # 回归
# 2. 准备数据集(测试集 和 训练集)
# train: 训练集
# test: 测试集
# neighbors: 最近邻的邻居数
x_train = [[0], [1], [2], [3]] # 训练集的特征数据, 因为特征可以有多个特征, 所以是一个二维数组
y_train = [0, 0, 1, 1] # 训练集的标签数据, 因为标签是离散的, 所以是一个一维数组
x_test = [[5]] # 测试集的特征数据
# 3. 创建(KNN 分类模型)模型对象.
# estimator: 估计器, 模型对象, 也可以用变量名 model做接收.
estimator = KNeighborsClassifier(n_neighbors=3) # n_neighbors: 最近邻的邻居数
# 4. 模型训练
# 传入: 训练集的特征数据, 训练集的标签数据
estimator.fit(x_train, y_train)
# 5. 模型预测.
# 传入: 测试集的特征数据, 获取到: 预测结果(测试集的标签, y_test)
y_pre = estimator.predict(x_test)
# 6. 打印预测结果.
print(f'预测值为: {y_pre}')
KNN回归
复制代码
KNN算法介绍(K Nearest Neighbors), K近邻算法
原理:
基于 欧式距离(或者其它距离计算方式)计算 测试集 和 每个训练集之间的距离, 然后根据距离升序排列, 找到最近的K个样本.
基于K个样本投票, 票数多的就作为最终预测结果 -> 分类问题.
基于K个样本计算平均值, 作为最终预测结果 -> 回归问题.
实现思路:
1. 分类问题
适用于: 有特征, 有标签, 且标签是不连续的(离散的)
2. 回归问题.
适用于: 有特征, 有标签, 且标签是连续的.
KNN算法, 回归问题思路如下:
1. 计算测试集和每个训练的样本之间的 距离.
2. 基于距离进行升序排列.
3. 找到最近的K个样本.
4. 基于K个样本的标签值, 计算平均值.
5. 将上述计算出来的平均值, 作为最终的预测结果.
代码实现思路:
1. 导包.
2. 准备数据集(测试集 和 训练集)
3. 创建(KNN 回归模型)模型对象.
4. 模型训练.
5. 模型预测.
总结:
K值过小, 容易受到异常值的影响, 且会导致模型学到大量的"脏的特征", 导致出现: 过拟合.
K值过大, 模型会变得简单, 容易发生: 欠拟合.
python
复制代码
"""
KNN算法介绍(K Nearest Neighbors), K近邻算法
原理:
基于 欧式距离(或者其它距离计算方式)计算 测试集 和 每个训练集之间的距离, 然后根据距离升序排列, 找到最近的K个样本.
基于K个样本投票, 票数多的就作为最终预测结果 -> 分类问题.
基于K个样本计算平均值, 作为最终预测结果 -> 回归问题.
实现思路:
1. 分类问题
适用于: 有特征, 有标签, 且标签是不连续的(离散的)
2. 回归问题.
适用于: 有特征, 有标签, 且标签是连续的.
KNN算法, 回归问题思路如下:
1. 计算测试集和每个训练的样本之间的 距离.
2. 基于距离进行升序排列.
3. 找到最近的K个样本.
4. 基于K个样本的标签值, 计算平均值.
5. 将上述计算出来的平均值, 作为最终的预测结果.
代码实现思路:
1. 导包.
2. 准备数据集(测试集 和 训练集)
3. 创建(KNN 回归模型)模型对象.
4. 模型训练.
5. 模型预测.
总结:
K值过小, 容易受到异常值的影响, 且会导致模型学到大量的"脏的特征", 导致出现: 过拟合.
K值过大, 模型会变得简单, 容易发生: 欠拟合.
"""
# 1. 导包.
from sklearn.neighbors import KNeighborsRegressor # KNN算法的 回归模型
# 2. 准备数据集(测试集 和 训练集)
# 开根号: 14.53 14.28 1 2.24
# 平方和: 211 204 1 5
# 差值: (3,11,9) (2,10,10) (0,1,0) (1,0,2)
x_train = [[0, 0, 1], [1, 1, 0], [3, 10, 10], [4, 11, 12]] # 训练集的特征数据, 因为特征可以有多个特征, 所以是一个二维数组
y_train = [0.1, 0.2, 0.3, 0.4] # 训练集的标签数据, 因为标签是连续的, 所以是一个一维数组
x_test = [[3, 11, 10]] # 测试集的特征数据
# 3. 创建(KNN 回归模型)模型对象.
estimator = KNeighborsRegressor(n_neighbors=2)
# 4. 模型训练.
estimator.fit(x_train, y_train)
# 5. 模型预测.
y_pre = estimator.predict(x_test)
# 6. 打印预测结果.
print(f'预测值为: {y_pre}')
特征预处理之归一化
复制代码
案例: 演示特征预处理之 归一化操作.
回顾: 特征工程的目的 和 步骤
目的:
利用专业的背景知识 和 技巧处理数据, 用于提升 模型的性能.
步骤:
1. 特征提取.
2. 特征预处理(归一化, 标准化)
3. 特征降维.
4. 特征选择.
5. 特征组合.
特征预处理之 归一化介绍:
目的:
防止因为量纲(单位)问题, 导致特征列的KNN距离值相差较大, 影响模型的最终结果.
所以通过公式把 各列的值 映射到 [0, 1] 区间.
公式:
x' = (当前值 - 该列最小值) / (该列最大值 - 该列最小值)
x'' = x' * (mx - mi) + mi
公式解释:
x' -> 基于公式算出来的 结果
x'' -> 最终的 结果.
mx -> 区间的最大值
mi -> 区间的最小值
弊端:
容易受到最大值 和 最小值的影响, 所以它一般用于处理 小数据集.
python
复制代码
"""
案例: 演示特征预处理之 归一化操作.
回顾: 特征工程的目的 和 步骤
目的:
利用专业的背景知识 和 技巧处理数据, 用于提升 模型的性能.
步骤:
1. 特征提取.
2. 特征预处理(归一化, 标准化)
3. 特征降维.
4. 特征选择.
5. 特征组合.
特征预处理之 归一化介绍:
目的:
防止因为量纲(单位)问题, 导致特征列的KNN距离值相差较大, 影响模型的最终结果.
所以通过公式把 各列的值 映射到 [0, 1] 区间.
公式:
x' = (当前值 - 该列最小值) / (该列最大值 - 该列最小值)
x'' = x' * (mx - mi) + mi
公式解释:
x' -> 基于公式算出来的 结果
x'' -> 最终的 结果.
mx -> 区间的最大值
mi -> 区间的最小值
弊端:
容易受到最大值 和 最小值的影响, 所以它一般用于处理 小数据集.
"""
# 导包
from sklearn.preprocessing import MinMaxScaler, StandardScaler # 归一化对象
# 1. 准备数据集(归一化之前的原数据).
x_train = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]
# 2. 创建归一化对象.
# 参数feature_range 表示生成范围, 默认为: 0, 1 如果就是这个区间, 则参数可以省略不写.
transfer = MinMaxScaler()
# transfer = MinMaxScaler(feature_range=(3, 5))
# 3. 对原数据集进行归一化操作.
x_train_new = transfer.fit_transform(x_train)
# 4. 打印处理后的数据.
print('归一化后的数据集为: \n')
print(x_train_new)
特征预处理之标准化
复制代码
案例: 演示特征预处理之 标准化操作.
回顾: 特征工程的目的 和 步骤
目的:
利用专业的背景知识 和 技巧处理数据, 用于提升 模型的性能.
步骤:
1. 特征提取.
2. 特征预处理(归一化, 标准化)
3. 特征降维.
4. 特征选择.
5. 特征组合.
特征预处理之 标准化介绍:
目的:
防止因为量纲(单位)问题, 导致特征列的KNN距离值相差较大, 影响模型的最终结果.
所以通过公式把 各列的值 映射到 均值为0, 标准差为1的 正态分布序列.
公式:
x' = (当前值 - 该列平均值) / 该列的标准差
应用场景:
适用于 大数据集 的处理.
结论:
无论是归一化, 还是标准化, 目的都是为了解决因为量纲(单位)问题, 导致模型评估较低等问题.
回顾:
方差计算公式: 该列每个值 和 该列均值的差 的平方和 的 平均值.
标准差计算公式: 方差开平方根
python
复制代码
"""
案例: 演示特征预处理之 标准化操作.
回顾: 特征工程的目的 和 步骤
目的:
利用专业的背景知识 和 技巧处理数据, 用于提升 模型的性能.
步骤:
1. 特征提取.
2. 特征预处理(归一化, 标准化)
3. 特征降维.
4. 特征选择.
5. 特征组合.
特征预处理之 标准化介绍:
目的:
防止因为量纲(单位)问题, 导致特征列的KNN距离值相差较大, 影响模型的最终结果.
所以通过公式把 各列的值 映射到 均值为0, 标准差为1的 正态分布序列.
公式:
x' = (当前值 - 该列平均值) / 该列的标准差
应用场景:
适用于 大数据集 的处理.
结论:
无论是归一化, 还是标准化, 目的都是为了解决因为量纲(单位)问题, 导致模型评估较低等问题.
回顾:
方差计算公式: 该列每个值 和 该列均值的差 的平方和 的 平均值.
标准差计算公式: 方差开平方根
"""
# 导包
from sklearn.preprocessing import StandardScaler # 标准化对象
# 1. 准备数据集(标准化之前的原数据).
x_train = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]
# 2. 创建标准化对象.
transfer = StandardScaler()
# 3. 对原数据集进行标准化操作.
x_train_new = transfer.fit_transform(x_train)
# 4. 打印处理后的数据.
print('标准化后的数据集为: \n')
print(x_train_new)
# 5. 打印数据集的均值和方差.
print(f'数据集的均值为: {transfer.mean_}')
print(f'数据集的方差为: {transfer.var_}')
print(f'数据集的标准差为: {transfer.scale_}')
KNN鸢尾花
复制代码
例: 通过KNN算法实现 鸢尾花的 分类操作.
回顾: 机器学习项目的研发流程
1. 加载数据.
2. 数据的预处理.
3. 特征工程(提取, 预处理...)
4. 模型训练.
5. 模型评估.
6. 模型预测.
python
复制代码
"""
案例: 通过KNN算法实现 鸢尾花的 分类操作.
回顾: 机器学习项目的研发流程
1. 加载数据.
2. 数据的预处理.
3. 特征工程(提取, 预处理...)
4. 模型训练.
5. 模型评估.
6. 模型预测.
"""
# 导入工具包
from sklearn.datasets import load_iris # 加载鸢尾花测试集的.
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split # 分割训练集和测试集的
from sklearn.preprocessing import StandardScaler # 数据标准化的
from sklearn.neighbors import KNeighborsClassifier # KNN算法 分类对象
from sklearn.metrics import accuracy_score # 模型评估的, 计算模型预测的准确率
# 1. 定义函数, 加载鸢尾花数据集, 并查看数据集.
def dm01_load_iris():
# 1. 加载鸢尾花数据集.
iris_data = load_iris()
# 2. 查看数据集.
# print(f'数据集: {iris_data}') # 字典形态
# print(f'数据集的类型: {type(iris_data)}') # <class 'sklearn.utils._bunch.Bunch'>
# 3. 查看数据集所有的键.
print(f'数据集所有的键: {iris_data.keys()}')
# 4. 查看数据集的键对应的值.
# print(f'具体的数据: {iris_data.data[:5]}') # 有150条数据, 每条数据有4个特征. 我们只看前5条
# print(f'具体的标签: {iris_data.target[:5]}') # 有150条数据, 每条数据有1个标签. 我们只看前5条
print(f'具体的数据: {iris_data.data}')
print(f'具体的标签: {iris_data.target}')
print(f'标签对应的名称: {iris_data.target_names}') # ['setosa' 'versicolor' 'virginica']
print(f'特征对应的名称: {iris_data.feature_names}') # ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
# print(f'数据集的描述: {iris_data.DESCR}')
# print(f'数据集的框架: {iris_data.frame}') # None
# print(f'数据集的文件名: {iris_data.filename}') # iris.csv
# print(f'数据集的模型(在哪个包下): {iris_data.data_module}') # sklearn.datasets.data
# 2. 定义函数, 绘制数据集的散点图.
def dm02_show_iris():
# 1. 加载数据集.
iris_data = load_iris()
# 2. 把 鸢尾花数据集封装成 DataFrame对象.
iris_df = pd.DataFrame(iris_data.data, columns=iris_data.feature_names)
# 3. 给df对象新增1列 -> 标签列.
iris_df['label'] = iris_data.target
# print(iris_df)
# 4. 通过 Seaborn绘制散点图.
# 参1: 数据集. 参2: x轴. 参3: y轴. 参4: 分组字段. 参5: 是否显示拟合线.
sns.lmplot(data=iris_df, x='sepal length (cm)', y='sepal width (cm)', hue='label', fit_reg=True)
# 5. 设置标题, 显式.
plt.title('iris data')
plt.tight_layout() # 自动调整子图参数, 以使整个图像的边界与子图匹配.
plt.show()
# 3. 定义函数, 切分训练集和测试集.
def dm03_split_train_test():
# 1. 加载数据集.
iris_data = load_iris()
# 2. 数据的预处理: 从150个特征和标签中, 按照 8:2的比例, 切分训练集和测试集.
# 参1: 特征数据. 参2: 标签数据. 参3: 测试集的比例. 参4: 随机种子(种子一致, 每次生成的随机数据集都是固定的)
# 返回值: 训练集的特征数据, 测试集的特征数据, 训练集的标签数据, 测试集的标签数据.
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=23)
# 3. 打印切割后的结果.
print(f'训练集的特征: {x_train}, 个数: {len(x_train)}') # 120条, 每条4列(特征)
print(f'训练集的标签: {y_train}, 个数: {len(y_train)}') # 120条, 每条1列(标签)
print(f'测试集的特征: {x_test}, 个数: {len(x_test)}') # 30条, 每条4列(特征)
print(f'测试集的标签: {y_test}, 个数: {len(y_test)}') # 30条, 每条1列(标签)
# 4. 定义函数, 实现鸢尾花完整案例 -> 加载数据, 数据预处理, 特征工程, 模型训练, 模型评估, 模型预测.
def dm04_iris_evaluate_test():
# 1. 加载数据集.
iris_data = load_iris()
# 2. 数据的预处理, 这里是把150条数据, 按照 8:2的比例, 切分训练集和测试集.
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=23)
# 3. 特征工程(提取, 预处理...)
# 思考1: 特征提取: 因为源数据只有4个特征列, 且都是我们用的, 所以这里无需做特征提取.
# 思考2: 特征预处理: 因为源数据的4列特征差值不大, 所以我们无需做特征预处理, 但是, 加入特征预处理会让我们的代码更完善, 所以加入.
# 3.1 创建标准化对象.
transfer = StandardScaler()
# 3.2 对特征列进行标准化, 即: x_train: 训练集的特征数据, x_test: 测试集的特征数据.
# fit_transform: 兼具fit和transform的功能, 即: 训练, 转换. 该函数适用于: 第一次进行标准化的时候使用. 一般用于处理: 训练集.
x_train = transfer.fit_transform(x_train)
# transform: 只有转换. 该函数适用于: 重复进行标准化动作时使用, 一般用于对测试集进行标准化.
x_test = transfer.transform(x_test)
# 4. 模型训练.
# 4.1 创建模型对象.
estimator = KNeighborsClassifier(n_neighbors=3)
# 4.2 具体的训练模型的动作.
estimator.fit(x_train, y_train) # 传入: 训练集的特征数据, 训练集的标签数据
# 5. 模型预测.
# 场景1: 对刚才切分的 测试集(30条) 进行测试.
# 5.1 直接预测即可, 获取到: 预测结果
y_pre = estimator.predict(x_test) # x_test: 测试集的特征数据
# 5.2 打印预测结果.
print(f'预测值为: {y_pre}')
# 场景2: 对新的数据集(源数据150条 之外的数据) 进行测试.
# 5.1 自定义测试数据集.
my_data = [[7.8, 2.1, 3.9, 1.6]]
# 5.2 对数据集进行标准化处理.
my_data = transfer.transform(my_data)
# 5.3 模型预测.
y_pre_new = estimator.predict(my_data)
print(f'预测值为: {y_pre_new}')
# 5.4 查看上述数据集, 每种分类的预测概率.
y_pre_proba = estimator.predict_proba(my_data)
print(f'(各分类)预测概率为: {y_pre_proba}') # [[0, 0.66666667, 0.33333333]] -> 0分类的概率, 1分类的概率, 2分类的概率.
# 6. 模型评估.
# 方式1: 直接评分, 基于: 测试集的特征 和 测试集集的标签.
print(f'正确率(准确率): {estimator.score(x_test, y_test)}') # 0.9666666666666667
# 方式2: 基于 测试集的标签 和 预测结果 进行评分.
print(f'正确率(准确率): {accuracy_score(y_test, y_pre)}') # 0.9666666666666667
# 5. 测试.
if __name__ == '__main__':
# dm01_load_iris()
# dm02_show_iris()
# dm03_split_train_test()
dm04_iris_evaluate_test()
网格搜索和交叉验证
复制代码
案例: 演示网格搜索 和 交叉验证.
交叉验证解释:
原理:
把数据分成n份, 例如分成: 4份 -> 也叫: 4折交叉验证.
第1次: 把第1份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率1
第2次: 把第2份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率2
第3次: 把第3份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率3
第4次: 把第4份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率4
然后计算上述的 4次准确率的 平均值, 作为: 模型最终的 准确率.
假设第4次最好(准确率最高), 则: 用全部数据(训练集 + 测试集)训练模型, 再次用(第4次的)测试集对模型测试.
目的:
为了让模型的最终验真结果更准确.
网格搜索:
目的/作用:
寻找最优超参数.
原理:
接收超参可能出现的值, 然后针对于 超参的每个值进行 交叉验证, 获取到 最优超参组合.
超参数:
需要用户手动录入的数据, 不同的超参(组合), 可能会影响模型的最终评测结果.
大白话解释:
网格搜索 + 交叉验证, 本质上指的是 GridSearchCV这个API, 它会帮我们寻找最优超参(供参考).
python
复制代码
"""
案例: 演示网格搜索 和 交叉验证.
交叉验证解释:
原理:
把数据分成n份, 例如分成: 4份 -> 也叫: 4折交叉验证.
第1次: 把第1份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率1
第2次: 把第2份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率2
第3次: 把第3份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率3
第4次: 把第4份数据作为 验证集(测试集), 其它作为训练集, 训练模型, 模型预测, 获取: 准确率 -> 准确率4
然后计算上述的 4次准确率的 平均值, 作为: 模型最终的 准确率.
假设第4次最好(准确率最高), 则: 用全部数据(训练集 + 测试集)训练模型, 再次用(第4次的)测试集对模型测试.
目的:
为了让模型的最终验真结果更准确.
网格搜索:
目的/作用:
寻找最优超参数.
原理:
接收超参可能出现的值, 然后针对于 超参的每个值进行 交叉验证, 获取到 最优超参组合.
超参数:
需要用户手动录入的数据, 不同的超参(组合), 可能会影响模型的最终评测结果.
大白话解释:
网格搜索 + 交叉验证, 本质上指的是 GridSearchCV这个API, 它会帮我们寻找最优超参(供参考).
"""
# 导入工具包
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 # KNN算法 分类对象
from sklearn.metrics import accuracy_score # 模型评估的, 计算模型预测的准确率
# 1. 加载鸢尾花数据集.
iris_data = load_iris()
# 2. 数据预处理, 这里是: 切分训练集和测试集, 比例: 8:2
# 参1: 数据集的特征数据, 参数2: 数据集的标签数据, 参数3: 测试集的比例, 参数4: 随机种子.
x_train, x_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.2, random_state=22)
# 3. 特征工程 -> 特征预处理 -> 标准化.
# 3.1 创建标准化对象.
transfer = StandardScaler()
# 3.2 对训练集和测试集的特征数据进行标准化.
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4. 模型训练.
# 4.1 创建 KNN分类对象.
estimator = KNeighborsClassifier()
# 4.2 定义字典, 记录 超参可能出现的情况(值).
param_dict = {'n_neighbors': [i for i in range(1, 11)]} # i的值: 1 ~ 10
# 4.3 创建 GridSearchCV对象 -> 寻找最优超参, 使用网格搜索 + 交叉验证方式
# 参1: 要计算最优超参的模型对象
# 参2: 该模型超参可能出现的值
# 参3: 交叉验证的折数, 这里的4折表示: 每个超参组合, 都会进行4次交叉验证. 这里共计是 4 * 10 = 40次.
# 返回值 estimator -> 处理后的模型对象.
estimator = GridSearchCV(estimator, param_dict, cv=4)
# 4.4 具体的模型训练动作.
estimator.fit(x_train, y_train)
# 4.5 打印最优超参组合.
print(f'最优评分: {estimator.best_score_}') # 0.9666666666666668
print(f'最优超参组合: {estimator.best_params_}') # {'n_neighbors': 3}
print(f'最优的估计器对象: {estimator.best_estimator_}') # KNeighborsClassifier(n_neighbors=3)
print(f'具体的交叉验证结果: {estimator.cv_results_}')
# 5. 模型评估.
# 5.1 获取最优超参的 模型对象.
# estimator = estimator.best_estimator_ # 获取最优的模型对象.
estimator = KNeighborsClassifier(n_neighbors=3)
# 5.2 模型训练.
estimator.fit(x_train, y_train)
# 5.3 模型预测.
y_pre = estimator.predict(x_test)
# 5.4 模型评估.
# 参1: 测试集. 参2: 预测集
print(f'准确率: {accuracy_score(y_test, y_pre)}') # 0.9666666666666667
手写数字识别
复制代码
案例: 演示 KNN算法 识别图片, 即: 手写数字识别案例.
介绍:
每张图片都是由 28 * 28 像素组成的, 即: 我们的csv文件中每一行都有 784个像素点, 表示图片(每个像素)的 颜色.
最终构成图像.
python
复制代码
"""
案例: 演示 KNN算法 识别图片, 即: 手写数字识别案例.
介绍:
每张图片都是由 28 * 28 像素组成的, 即: 我们的csv文件中每一行都有 784个像素点, 表示图片(每个像素)的 颜色.
最终构成图像.
"""
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import joblib
from collections import Counter
# 扩展: 忽略警告.
import warnings
warnings.filterwarnings('ignore', module='sklearn') # 参1: 忽略警告, 参2: 忽略的模块.
# 1. 定义函数, 接收用户传入的索引, 展示 该索引对应的图片.
def show_digit(idx):
# 1. 读取数据集, 获取到源数据.
df = pd.read_csv('./data/手写数字识别.csv')
# print(df) # (42000行 * 785列)
# 2. 判断传入的索引是否越界.
if idx < 0 or idx > len(df) - 1:
print('索引越界!')
return
# 3. 走这里, 说明没有越界, 就正常获取数据.
x = df.iloc[:, 1:]
y = df.iloc[:, 0]
# 4. 查看用户传入的索引对应的图片 -> 是几?
print(f'该图片对应的数字是: {y.iloc[idx]}')
print(f'查看所有的标签的分布情况: {Counter(y)}')
# 5. 查看下 用户传入的索引对应的图片 的形状
print(x.iloc[idx].shape) # (784,) 我们要想办法把 (784,) 转换成 (28, 28)
# print(x.iloc[idx].values) # 具体的784个像素点数据
# 6. 把 (784,) 转换成 (28, 28)
x = x.iloc[idx].values.reshape(28, 28)
# print(x) # 28 * 28像素点
# 7. 具体的绘制灰度图的动作.
plt.imshow(x, cmap='gray') # 灰度图
plt.axis('off') # 不显示坐标轴
plt.show()
# 2. 定义函数, 训练模型, 并保存训练好的模型.
def train_model():
# 1. 加载数据集.
df = pd.read_csv('./data/手写数字识别.csv')
# 2. 数据的预处理.
# 2.1 拆分出特征列.
x = df.iloc[:, 1:] # 特征列.
# 2.2 拆分出标签列.
y = df.iloc[:, 0] # 标签列.
# 2.3 打印特征和标签的形状
print(f'x的形状: {x.shape}') # (42000, 784)
print(f'y的形状: {y.shape}') # (42000,)
print(f'查看所有的标签的分布情况: {Counter(y)}')
# 2.4 对特征列(拆分前)进行 归一化.
x = x / 255
# 2.5 拆分训练集和测试集.
# 参1: 特征列. 参2: 标签列. 参3: 测试集的比例. 参4: 随机种子. 参5: 参考y值进行抽取, 保持标签的比例(数据均衡)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=21, stratify=y)
# 3. 模型训练.
# 3.1 创建模型对象.
estimator = KNeighborsClassifier(n_neighbors=3)
# 3.2 模型训练.
estimator.fit(x_train, y_train)
# 4. 模型评估.
print(f'准确率: {estimator.score(x_test, y_test)}')
print(f'准确率: {accuracy_score(y_test, estimator.predict(x_test))}')
# 5. 保存模型.
# 参1: 模型对象. 参2: 模型保存的路径.
joblib.dump(estimator, './model/手写数字识别.pkl') # pickle文件: Python(Pandas)独有的文件类型.
print('模型保存成功!')
# 3. 定义函数, 测试模型.
def use_model():
# 1. 加载图片.
x = plt.imread('./data/demo.png') # 28 * 28像素
# 2. 绘制图片.
# plt.imshow(x, cmap='gray') # 灰度图
# plt.axis('off') # 不显示坐标轴
# plt.show()
# 3. 加载模型.
estimator = joblib.load('./model/手写数字识别.pkl')
# 4. 模型预测.
# 4.1 查看 数据集转换.
print(x.shape) # (28, 28)
print(x.reshape(1, 784).shape) # (1, 784)
print(x.reshape(1, -1).shape) # 效果等同于 (1, 784), 语法糖.
# 4.2 具体的转换动作, 记得: 归一化(因为训练模型的时候 使用了 归一化动作)
# x = x.reshape(1, -1) / 255 # 可能会预测失败, 因为读图的时候, 像素值可能不是特别的精准.
x = x.reshape(1, -1) # 用原始的读取到的像素值, 做预测.
# 4.3 模型预测.
y_pre = estimator.predict(x)
# 5. 打印预测结果.
print(f'预测值为: {y_pre}')
# 4. 测试.
if __name__ == '__main__':
# 绘制数字
# show_digit(9)
# show_digit(20)
# show_digit(23)
# 训练模型, 并保存模型.
# train_model()
# 模型预测(使用模型)
use_model()