KNN数学公式完整计算(以电影数据为例)
目标 :预测新电影 [23, 3, 17] 的类型
特征 :搞笑镜头数、拥抱镜头数、打斗镜头数
类别 :0=喜剧片、1=动作片、2=爱情片
参数:K=3(取3个最近邻居)
数据表格化
| 样本 | 搞笑镜头(x₁) | 拥抱镜头(x₂) | 打斗镜头(x₃) | 标签(y) | 类型 |
|---|---|---|---|---|---|
| 1 | 39 | 0 | 31 | 0 | 喜剧片 |
| 2 | 3 | 2 | 65 | 1 | 动作片 |
| 3 | 2 | 3 | 55 | 2 | 爱情片 |
| 4 | 9 | 38 | 2 | 2 | 爱情片 |
| 5 | 8 | 34 | 17 | 2 | 爱情片 |
| 6 | 5 | 2 | 57 | 1 | 动作片 |
| 7 | 21 | 17 | 5 | 0 | 喜剧片 |
| 8 | 45 | 2 | 9 | 0 | 喜剧片 |
待预测:Q = [23, 3, 17]
数学公式体系
1. 距离公式(欧氏距离)
d(x, y) = √[(x₁ - y₁)² + (x₂ - y₂)² + (x₃ - y₃)²]
2. K近邻集合
Nₖ(q) = {(x⁽ⁱ⁾, y⁽ⁱ⁾) | 距离d(q, x⁽ⁱ⁾) 最小的K个样本}
3. 投票决策
ŷ = argmax_{c∈{0,1,2}} ∑_{(x⁽ⁱ⁾,y⁽ⁱ⁾)∈Nₖ(q)} I(y⁽ⁱ⁾ = c)
其中 I(条件) 是指示函数(条件成立=1,否则=0)
逐步计算过程
第1步:计算所有距离
通用公式:d_i = √[(23 - x₁_i)² + (3 - x₂_i)² + (17 - x₃_i)²]
计算样本1(喜剧片):
d₁ = √[(23-39)² + (3-0)² + (17-31)²]
= √[(-16)² + 3² + (-14)²]
= √[256 + 9 + 196]
= √461 ≈ 21.47
计算样本2(动作片):
d₂ = √[(23-3)² + (3-2)² + (17-65)²]
= √[20² + 1² + (-48)²]
= √[400 + 1 + 2304]
= √2705 ≈ 52.01
计算样本3(爱情片):
d₃ = √[(23-2)² + (3-3)² + (17-55)²]
= √[21² + 0² + (-38)²]
= √[441 + 0 + 1444]
= √1885 ≈ 43.42
计算样本4(爱情片):
d₄ = √[(23-9)² + (3-38)² + (17-2)²]
= √[14² + (-35)² + 15²]
= √[196 + 1225 + 225]
= √1646 ≈ 40.57
计算样本5(爱情片):
d₅ = √[(23-8)² + (3-34)² + (17-17)²]
= √[15² + (-31)² + 0²]
= √[225 + 961 + 0]
= √1186 ≈ 34.44
计算样本6(动作片):
d₆ = √[(23-5)² + (3-2)² + (17-57)²]
= √[18² + 1² + (-40)²]
= √[324 + 1 + 1600]
= √1925 ≈ 43.87
计算样本7(喜剧片):
d₇ = √[(23-21)² + (3-17)² + (17-5)²]
= √[2² + (-14)² + 12²]
= √[4 + 196 + 144]
= √344 ≈ 18.55
计算样本8(喜剧片):
d₈ = √[(23-45)² + (3-2)² + (17-9)²]
= √[(-22)² + 1² + 8²]
= √[484 + 1 + 64]
= √549 ≈ 23.43
第2步:距离排序表
| 排名 | 样本 | 特征向量 | 标签 | 距离 | 类型 |
|---|---|---|---|---|---|
| 1 | 7 | [21, 17, 5] | 0 | 18.55 | 喜剧片 |
| 2 | 1 | [39, 0, 31] | 0 | 21.47 | 喜剧片 |
| 3 | 8 | [45, 2, 9] | 0 | 23.43 | 喜剧片 |
| 4 | 5 | [8, 34, 17] | 2 | 34.44 | 爱情片 |
| 5 | 4 | [9, 38, 2] | 2 | 40.57 | 爱情片 |
| 6 | 3 | [2, 3, 55] | 2 | 43.42 | 爱情片 |
| 7 | 6 | [5, 2, 57] | 1 | 43.87 | 动作片 |
| 8 | 2 | [3, 2, 65] | 1 | 52.01 | 动作片 |
第3步:选取K=3个最近邻
根据排序,最近的3个邻居是:
N₃(q) = { (样本7, 标签0), (样本1, 标签0), (样本8, 标签0) }
用数学集合表示:
N₃(q) = {(x⁽⁷⁾,0), (x⁽¹⁾,0), (x⁽⁸⁾,0)}
= {([21,17,5],0), ([39,0,31],0), ([45,2,9],0)}
第4步:多数投票
投票公式:对于每个类别c,计算:v_c = ∑_{(x,y)∈N₃(q)} I(y = c)
计算各类别票数:
v₀ = I(0=0) + I(0=0) + I(0=0) = 1 + 1 + 1 = 3
v₁ = I(0=1) + I(0=1) + I(0=1) = 0 + 0 + 0 = 0
v₂ = I(0=2) + I(0=2) + I(0=2) = 0 + 0 + 0 = 0
票数统计:
类别0(喜剧片):3票
类别1(动作片):0票
类别2(爱情片):0票
第5步:决策结果
决策公式:
ŷ = argmax_{c∈{0,1,2}} {v₀=3, v₁=0, v₂=0}
计算最大值:
max(3, 0, 0) = 3
argmax = 对应的类别 = 0
最终预测:ŷ = 0 (喜剧片)
实现代码
例一
python
def dm01_knn_clas():
# 1 导入依赖包
from sklearn.neighbors import KNeighborsClassifier
# 2 准备数据 # 0-喜剧片 1-动作片 2-爱情片
x = [[39, 0, 31], # 0
[3, 2, 65], # 1
[2, 3, 55], # 2
[9, 38, 2], # 2
[8, 34, 17], # 2
[5, 2, 57], # 1
[21, 17, 5], # 0
[45, 2, 9]] # 0
y = [0, 1, 2, 2, 2, 1, 0, 0]
# 3 实例化模型
estimator = KNeighborsClassifier(n_neighbors=3)
print('estimator-->', estimator)
# 4 模型训练 .fit()
estimator.fit(x, y)
# 5 模型预测 .predict() 搞笑镜头23 拥抱镜头3 打动镜头17
pred = estimator.predict([[23, 3, 17]])
print('pred-->', pred)
列二
python
def dm02_knn_clas():
# 1.导入依赖包
from sklearn.neighbors import KNeighborsClassifier
# 2.准备数据 # 0-喜剧片 1-动作片 2-爱情片
x = [[39, 0, 31], # 0
[3, 2, 65], # 1
[2, 3, 55], # 2
[9, 38, 2], # 2
[8, 34, 17], # 2
[5, 2, 57], # 1
[21, 17, 5], # 0
[45, 2, 9]] # 0
y = [0, 1, 2, 2, 2, 1, 0, 0]
# 分为3类
estimator = KNeighborsClassifier(n_neighbors=3)
print('estimator-->', estimator)
# 4.模型训练
estimator.fit(x, y)
score = estimator.score(x, y)
print('score-->', score)
# 5 模型预测 .predict() 搞笑镜头23 拥抱镜头3 打动镜头17
pred = estimator.predict([[23, 3, 17]])
print('pred-->', pred)
pred = estimator.predict([[23, 3, 17], [8, 34, 17]])
print('pred-->', pred)
# 6. 保存模型
import joblib
joblib.dump(estimator, './model/knn_model.bin')
print('\n模型已保存为: ./model/knn_model.bin')
# 9. 验证模型加载和预测
loaded_model = joblib.load('./model/knn_model.bin')
test_pred = loaded_model.predict([[23, 3, 17], [8, 34, 17]])
print(f'加载模型后的预测验证: {test_pred}')