- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
前言
- 机器学习是深度学习和数据分析的基础,接下来将更新常见的机器学习算法
- 注意:在打数学建模比赛中,机器学习用的也很多,可以一起学习
- 欢迎收藏 + 点赞 + 关注
文章目录
- K-邻近算法模型简介
- 1、模型简介
- 2、模型难点与求解
- KNN难点
- 解决方法
- K值选取问题
- 选取K值后,如何遍历速度最快
- 距离选取
- 欧式距离
- 曼哈顿距离
- 切比雪夫距离
- 案例求解
- 1、导入数据
- 2、统计分析
- 3、数据预处理
- 4、划分数据集
- 5、模型的创建与训练
- 6、预测结果
- 7、模型评估
K-邻近算法模型简介
1、模型简介
解决了什么问题?
- K-邻近,简称KNN,KNN解决了的分类与回归问题,主要运用解决分类问题
例子说明
首先上图,上图有三类不同形状,O
是要预测他属于那一类,KNN算法的思想就是
,选取与他最近的K的点,那个类别占比大,他就属于那个类别。上图中:
- K值为3时候,三角形最多,故它属于三角形类
- K值为5的时候,正方形最多,故它属于正方形那一类
2、模型难点与求解
KNN难点
- K值的选取问题
- 选取K值后,如何遍历速度最快?
- 距离如何计算问题
解决方法
K值选取问题
在李航老师的《统计学习方法》上所说:
- 选择较小的K值,就相当于用较小的领域中的训练实例进⾏预测, “学习”近似误差会减小,只有与输⼊实例较近或相似的训练实例才会对预 测结果起作⽤,与此同时带来的问题是“学习”的估计误差会增⼤, 换句话说,**K值的减小就意味着整体模型变得复杂,容易发生过拟合; **
- 选择较大的K值,就相当于⽤较⼤领域中的训练实例进⾏预测, 其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增⼤。这时候,与输⼊实例较远(不相似的)训练实例也会对预测器作⽤,使预测发⽣错误。 且**K值的增大就意味着整体的模型变得简单。 **
- K=N(N为训练样本个数),则完全不足取, 因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的类,模型过于简单,忽略了训练实例中大量有用信息。 在实际应⽤中,K值⼀般取⼀个比较小的数值,例如采⽤交叉验证法(简单来 说,就是把训练数据在分成两组:训练集和验证集)来选择最优的K值。
方法:网格搜索
网格搜索解决的问题是,当有多个参数选择的时候,选取最优解的参数,如下:
model = KNeighborsClassifier() # algorithm:自动选择算法确定K值
# 网格搜索查找最优 n_neighors
grid_search = {"n_neighbors": [1, 3, 5, 7, 9]}
model = GridSearchCV(model, param_grid=grid_search, cv=5) # 交叉验证设置为 5
选取K值后,如何遍历速度最快
这个方法在sklearn库中很好解决,在使用KNeighborsClassifier()
创建模型的时候,KNeighborsClassifier()
参数列表中有一个algorithm
的参数,它包含了一下几个参数,默认是auto,有兴趣的同学可以查阅资料学习Kd_tree的原理,推荐在b站中kd树相关的教程。
- ‘auto’:
- 当选择
'auto'
时,scikit-learn 会根据训练数据的大小和维度自动选择最合适的算法。这是默认选项,通常是一个好的起点,因为它可以根据数据的特性来选择最佳算法。
- 当选择
- ‘ball_tree’:
- 使用 Ball Tree 数据结构。适用于高维空间中的最近邻搜索。Ball Tree 是一种树形数据结构,它可以有效地处理高维数据。
- ‘kd_tree’:
- 使用 KD Tree 数据结构。适用于低至中等维度的空间中的最近邻搜索。KD Tree 也是一种树形数据结构,但更适合低维数据。
- ‘brute’:
- 使用蛮力(Brute Force)方法来计算最近邻。这种方法直接计算每个样本之间的距离,没有使用任何加速数据结构。虽然简单,但在大样本集或高维数据中效率较低。
距离选取
通过查阅资料,发现主要的距离选取分为以下几种类型:
欧式距离
欧氏距离(Euclidean Distance)是最容易直观理解的距离度量方法,我们小学、初中和高中接触到的两个点在空间中的距离一般都是指欧氏距离,他的公式如下:
曼哈顿距离
在曼哈顿街区要从一个十字路口开车到另一个十字路口,驾驶距离显然不是两点间的直线距离。这个实际驾驶距离就是“曼哈顿距离(Manhattan Distance)”。曼哈顿距离也称为“城市街区距离”(City Block distance)。
切比雪夫距离
国际象棋中,国王可以直行、横行、斜行,所以国王走一步可以移动到相邻8个方格中的任意一个。国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?这个距离就叫切比雪夫距离(Chebyshev Distance)。
案例求解
背景: 海伦一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但她没有从中找到喜欢的人。经过一番总结,她发现曾交往过三种类型的人:
- ①不喜欢的人;
- ②魅力一般的人;
- ③极具魅力的人。
她现在总结好的数据中(即训练集)包含三种特征:
- ①每年获得的飞行常客里程数
- ②玩视频游戏所耗时间百分比
- ③每周消费的冰淇淋公升数
她希望根据现有的数据来判断一个陌生男人会被她归到哪一类。
求解步骤:
- 导入数据
- 统计分析
- 数据预处理
- 划分数据集
- 模型的创建与训练
- 预测结果
- 模型评估
1、导入数据
import pandas as pd
data = pd.read_table('./datingTestSet2.txt', sep='\t', header=None)
data.head()
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 40920 | 8.326976 | 0.953952 | 3 |
1 | 14488 | 7.153469 | 1.673904 | 2 |
2 | 26052 | 1.441871 | 0.805124 | 1 |
3 | 75136 | 13.147394 | 0.428964 | 1 |
4 | 38344 | 1.669788 | 0.134296 | 1 |
分析:pd.read_table(‘./datingTestSet2.txt’, sep=‘\t’, header=None)
- 第一个参数:路径
- sep:表示数据字段中用什么分割
- header:第一行是否是标题,不是,则用0、1、2……代替
2、统计分析
# 查看维度
data.shape
答案:
(1000, 4)
# 查看数据基本信息
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 0 1000 non-null int64
1 1 1000 non-null float64
2 2 1000 non-null float64
3 3 1000 non-null int64
dtypes: float64(2), int64(2)
memory usage: 31.4 KB
# 查看统计
data.describe()
0 | 1 | 2 | 3 | |
---|---|---|---|---|
count | 1000.000000 | 1000.000000 | 1000.000000 | 1000.000000 |
mean | 33635.421000 | 6.559961 | 0.832073 | 1.985000 |
std | 21957.006833 | 4.243618 | 0.497239 | 0.818196 |
min | 0.000000 | 0.000000 | 0.001156 | 1.000000 |
25% | 13796.000000 | 2.933963 | 0.408995 | 1.000000 |
50% | 31669.000000 | 6.595204 | 0.809420 | 2.000000 |
75% | 47716.250000 | 10.056501 | 1.272847 | 3.000000 |
max | 91273.000000 | 20.919349 | 1.695517 | 3.000000 |
# 查看缺失值
data.isnull().sum()
答案:
0 0
1 0
2 0
3 0
dtype: int64
经过分析,每一列都没有缺失值
# 每个特征之间的相关性
data.iloc[:, :3].corr()
0 | 1 | 2 | |
---|---|---|---|
0 | 1.000000 | 0.465847 | -0.009171 |
1 | 0.465847 | 1.000000 | 0.008874 |
2 | -0.009171 | 0.008874 | 1.000000 |
3、数据预处理
KNN,特征值来源于生活统计,特征一与特征二、三差距很大,故为了确保特征值在计算距离的时候准确率高一点,故这里对特征数据进行归一化
处理
from sklearn.preprocessing import MinMaxScaler
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# 标准化,对特征
scaler = MinMaxScaler()
data_scaled = scaler.fit_transform(data.iloc[:, :3])
# 将标准化后的数据转为DataFrame
data_scaled = pd.DataFrame(data_scaled)
# 标准化后数据统计信息
print("标准化后数据统计信息:\n", data_scaled.describe())
# 可视化前后数据分布
plt.figure(figsize=(16, 6))
# 标准化前的分布
plt.subplot(1, 2, 1)
sns.histplot(data.iloc[:, 0], kde=True, color='blue')
plt.title('Distribution of Median Income before Standardization')
# 标准化后的分布
plt.subplot(1, 2, 2)
sns.histplot(data_scaled.iloc[:, 0], kde=True, color='red')
plt.title('Distribution of Median Income after Standardization')
plt.show()
标准化后数据统计信息:
0 1 2
count 1000.000000 1000.000000 1000.000000
mean 0.368514 0.313583 0.490401
std 0.240564 0.202856 0.293467
min 0.000000 0.000000 0.000000
25% 0.151151 0.140251 0.240703
50% 0.346970 0.315268 0.477032
75% 0.522786 0.480727 0.750543
max 1.000000 1.000000 1.000000
# 赋值给原数据
data.iloc[:, :3] = data_scaled.iloc[:, :3]
data
0 | 1 | 2 | 3 | |
---|---|---|---|---|
0 | 0.448325 | 0.398051 | 0.562334 | 3 |
1 | 0.158733 | 0.341955 | 0.987244 | 2 |
2 | 0.285429 | 0.068925 | 0.474496 | 1 |
3 | 0.823201 | 0.628480 | 0.252489 | 1 |
4 | 0.420102 | 0.079820 | 0.078578 | 1 |
... | ... | ... | ... | ... |
995 | 0.122106 | 0.163037 | 0.372224 | 2 |
996 | 0.754287 | 0.476818 | 0.394621 | 1 |
997 | 0.291159 | 0.509103 | 0.510795 | 3 |
998 | 0.527111 | 0.436655 | 0.429005 | 3 |
999 | 0.479408 | 0.376809 | 0.785718 | 3 |
1000 rows × 4 columns
4、划分数据集
from sklearn.model_selection import train_test_split
X = data.iloc[:, :3]
y = data.iloc[:, 3]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
5、模型的创建与训练
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
model = KNeighborsClassifier() # algorithm:自动选择算法确定K值
# 网格搜索查找最优 n_neighors
grid_search = {"n_neighbors": [1, 3, 5, 7, 9]}
model = GridSearchCV(model, param_grid=grid_search, cv=5) # 交叉验证设置为 5
model.fit(X_train, y_train)
6、预测结果
# 对整个模型进行预测
data["预测结果"] = model.predict(data.iloc[:, :3])
data.head(10)
0 | 1 | 2 | 3 | 预测结果 | |
---|---|---|---|---|---|
0 | 0.448325 | 0.398051 | 0.562334 | 3 | 3 |
1 | 0.158733 | 0.341955 | 0.987244 | 2 | 2 |
2 | 0.285429 | 0.068925 | 0.474496 | 1 | 1 |
3 | 0.823201 | 0.628480 | 0.252489 | 1 | 1 |
4 | 0.420102 | 0.079820 | 0.078578 | 1 | 1 |
5 | 0.799722 | 0.484802 | 0.608961 | 1 | 1 |
6 | 0.393851 | 0.326530 | 0.715335 | 3 | 3 |
7 | 0.467455 | 0.634645 | 0.320312 | 3 | 3 |
8 | 0.739507 | 0.412612 | 0.441536 | 1 | 1 |
9 | 0.388757 | 0.586690 | 0.889360 | 3 | 3 |
# 查看后 10 行
data.tail(10)
0 | 1 | 2 | 3 | 预测结果 | |
---|---|---|---|---|---|
990 | 0.304033 | 0.408557 | 0.075279 | 3 | 3 |
991 | 0.108115 | 0.128827 | 0.254764 | 2 | 2 |
992 | 0.200859 | 0.188880 | 0.196029 | 2 | 2 |
993 | 0.041414 | 0.471152 | 0.193598 | 2 | 2 |
994 | 0.199292 | 0.098902 | 0.253058 | 2 | 2 |
995 | 0.122106 | 0.163037 | 0.372224 | 2 | 2 |
996 | 0.754287 | 0.476818 | 0.394621 | 1 | 1 |
997 | 0.291159 | 0.509103 | 0.510795 | 3 | 3 |
998 | 0.527111 | 0.436655 | 0.429005 | 3 | 3 |
999 | 0.479408 | 0.376809 | 0.785718 | 3 | 3 |
7、模型评估
scorek = model.score(X_test, y_test)
scorek
答案:
0.93