机器学习算法1-KNN

Posted by Hilda on August 1, 2025

总结:机器学习代码套路

  • 准备数据
    • (DataFrame可以直接参与训练,但是一般要求都是二维的;一般可以尝试用numpy的ndarray进行训练,df转换成ndarray的方法:df.values即可)如果是df,第一个维度一般是样本数量,第二个维度一般是特征数量。对于有监督学习的标签y_train,一般是一维的,也可以是字符串,但是不能是Series
  • 创建机器学习算法实例
  • 训练
  • 预测
  • 评估

推荐看视频了解KNN算法的原理:https://www.youtube.com/watch?v=gs9E7E0qOIc

K 近邻算法(K-Nearest Neighbors, KNN) 是一种简单的非参数惰性学习算法。它不需要显式的训练过程,而是将所有训练数据存储起来,在需要预测时才进行计算。

KNN核心原理:该算法认为在特征空间中,彼此相近(即距离较小)的样本具有相似的标签。一个新样本的类别由它最接近的 K 个邻居的类别决定。

KNN 的三个基本要素

  1. 距离度量(Distance Metric):如何计算样本之间的相似度。
  2. k 值的选择(Choice of k):选择多少个邻居参与决策。
  3. 分类决策规则(Decision Rule):如何根据 K 个邻居的标签来决定新样本的标签。

1.距离度量

1.1 欧氏距离(Euclidean Distance)

image-20250801165756757

最常用的距离,表示多维空间中的直线距离。

\[d(x,y)=\sqrt {∑_{i=1}^{n}(x_i−y_i)2}\]

适用于连续、数值型特征。

1.2 曼哈顿距离(Manhattan Distance)

image-20250801165817652

表示在网格中从一个点到另一个点的距离,只能沿坐标轴方向移动。

\[d(x,y)=∑_{i=1}^n∣x_i−y_i∣\]

1.3 闵可夫斯基距离(Minkowski Distance)

image-20250801170053266

是欧氏距离和曼哈顿距离的推广。

\[d(x,y)=(∑_{i=1}^n∣x_i−y_i∣^p)^{1/p}\]

当 p=1 时是曼哈顿距离,当 p=2 时是欧氏距离。

1.4 余弦相似度(Cosine Similarity)

衡量两个向量方向上的差异,而非大小。

\[similarity=cos(θ)=\frac{A·B}{∥A∥_2∥B∥_2}\]

适用于文本分析等场景,此时向量的长度(范数)不重要,方向更重要。

1.5 汉明距离(Hamming Distance)

计算两个等长字符串中对应位置不同字符的数量。 适用于离散、类别型特征。

2.实战案例1-分类任务

使用 Python 的 scikit-learn 库来实现 KNN 算法,因为它高效且易于使用。

按照sklearn库:

1
!pip install scikit-learn

image-20250801170804754

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split


from sklearn.metrics import accuracy_score
# 生成一个模拟的分类数据集
# n_features:每个样本的特征数量是2个
# n_informative=2 对分类任务有信息的特征数量
# n_redundant 冗余特征的数量
# random_state随机种子为 42,保证结果的可复现
X, y = make_classification(n_samples=500, n_features=2, n_informative=2, n_redundant=0, random_state=42)
# X 将是一个形状为 (100, 2) 的矩阵,y:形状为 (100,) 的数组,且y只有0, 1两个元素
# display(X, y)


# 把数据划分为训练集和测试集
X_train,  X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# display(X_train.shape)# (70, 2)

# 1.初始化KNN分类器
# n_neighbors=5  k值,邻居数量
# weights="uniform"   投票权重,uniform表示等权重,distance根据距离加权
# metric="euclidean"   距离的度量 :欧式距离/曼哈顿距离
knn_classifier = KNeighborsClassifier(n_neighbors=5, weights="uniform", metric="euclidean")

# 2.训练模型
knn_classifier.fit(X_train, y_train)

# 3.进行预测
y_pred_class = knn_classifier.predict(X_test)

# 4.评估模型    如果n_samples变大,显然会导致准确率下降
acc = accuracy_score(y_test, y_pred_class)
print(f"准确率:{acc:.5f}")

# 可视化分类结果
h = 0.02
# 对特征的最小值减 1(X[:, 0].min() - 1),对最大值加 1(X[:, 0].max() + 1),是为了在可视化时扩展网格范围
x_min,x_max = X[:,0].min() - 1, X[:,0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = knn_classifier.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.figure(figsize=(10, 8))
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=plt.cm.coolwarm, edgecolor='k', s=80)
plt.title("KNN分类器决策边界可视化")
plt.xlabel("特征1")
plt.ylabel("特征2")
plt.show()


image-20250801204311948

3.实战案例2-分类任务

准备了下面的数据:

image-20250801215153442

可视化为散点图:

1
2
3
4
data.plot(kind="scatter", x = "武打镜头", y = "接吻镜头", cmap="rainbow", c = [1, 1, 0, 1, 0, 0])
for i, row in data.iterrows():
#     print(i, row)
    plt.text(row["武打镜头"], row["接吻镜头"], row["电影名称"])

image-20250801220115273

【1】准备数据:

1
2
3
4
5
6
7
8
# 训练数据与测试数据准备
X_train = data[["武打镜头", "接吻镜头"]].values  # 要求一定是二维的
y_train = data["分类情况"].values   # 要求不能是Series

# 测试数据:
data_test = pd.read_csv("./filtered_movie_data.csv", delimiter=",")
X_test = data_test[["武打镜头", "接吻镜头"]].values
y_test = data_test["分类情况"].values

【2】创建KNN算法的实例

1
knn = KNeighborsClassifier()  # 默认是k=5

如果需要调整其他参数,参考下面的表格

KNeighborsClassifier参数

参数 描述 默认值
n_neighbors k 值,即用于分类的邻居数量。该值通常是一个正整数。 5
weights 权重函数,用于预测。 'uniform'
  'uniform':所有邻居的权重相同。  
  'distance':根据距离的倒数分配权重,即距离越近的邻居影响越大。  
  [callable]:用户自定义的权重函数。  
algorithm 用于计算最近邻的算法。在数据量不大时,'auto' 是一个不错的选择。 'auto'
  'auto':根据输入数据自动选择最合适的算法。  
  'ball_tree':使用 BallTree 算法。  
  'kd_tree':使用 KDTree 算法。  
  'brute':使用蛮力搜索。  
leaf_size 传递给 BallTreeKDTree 的叶子大小。这个参数会影响树的构建速度和查询速度,以及存储树所需的内存。 30
p Minkowski 距离的幂参数。p=1 等同于曼哈顿距离 (l1),p=2 等同于欧氏距离 (l2)。 2
metric 用于树的距离度量。默认值为 'minkowski',当 p=2 时,它等同于标准的欧氏距离。 'minkowski'
n_jobs 用于邻居搜索的并行工作数。-1 表示使用所有处理器。在 fit 方法中不使用。 None

【3】训练:

1
knn.fit(X_train, y_train)

image-20250801222443511

【4】预测:

1
knn.predict(X_test)

image-20250801222528962

【5】评估

1
accuracy_score(y_test, knn.predict(X_test))

image-20250801222658023

4.建立对机器学习的正确认识

机器学习预测错误是很正常的!!!原始的训练数据本身就会影响预测结果。所以训练数据应该尽量多样化。

5.KNN的优缺点

image-20250801224831603