数学建模社区-数学中国
标题:
K-近邻算法分类和回归
[打印本页]
作者:
杨利霞
时间:
2022-9-5 15:43
标题:
K-近邻算法分类和回归
3 p1 _' ~2 N% H% P& s3 K% G' |& J
K-近邻算法分类和回归
4 ^* o# y4 V2 T2 j
K近邻算法的主要思想是用离测试集数据点最近的训练集点(称为其邻居)的输出来估计测试集数据点的输出,参数K代表用多少个邻居来估计。超参数K通常设置为奇数来防止平局现象。
- @, K+ T* |6 J" M) K
. B3 H# v0 a; J0 C) F
其中对邻居的判定:我们可以用欧几里得距离来衡量距离来确定其K个邻居。
0 D$ y+ P i8 |; z2 M2 Q% `
5 P$ n/ X o0 i8 Z6 L* i0 J% s
K近邻算法是一种惰性学习和非参数模型。当训练数据数量庞大,同时你对响应变量和解释变量之间的关系所知甚少时,非参数模型会非常有用。KNN 模型只基于一个假设:互相接近的实例拥有类似的响应变量值。非参数模型提供的灵活性并不总是可取的,当训练数据很缺乏或者你对响应变量和解释变量之间的关系有所了解时,对响应变量和解释变量之间关系做假设的模型就很有用。
" x, F; ]- U1 ~7 f& E; q6 |
9 k3 p' Y$ q9 @8 |1 y/ E# j
KNN模型分类:
/ D- Q9 y* [! Y
下面我们看一个分类的例子和代码实现来了解一下K近邻算法:
4 X# a _. O( X- R) I y! Q
; s6 l/ }5 @: z& ]
) S) q% S2 N, O; B1 o5 i
* W( o) I, K, b- s7 ^2 u
上表是我们的训练集,下面先对数据进行可视化
) p9 h7 L9 l4 @+ a4 r3 K
( x! \2 O+ @/ q U6 R# s
import numpy as np
: k# P' H& [4 q- P# `8 ]
from matplotlib import pyplot as plt
& Q' \) s# p. `3 \
import sklearn
7 L) s( @; V5 ]2 W2 q" H9 ?
/ Z9 c2 X' h1 U. }3 E5 |' J4 w/ ]
X_train = np.array([ # 身高体重
) {9 N- k1 k3 b9 r0 g9 C( f
[158, 64],
0 H; E1 P/ P! e
[170, 86],
! C0 ?6 ^& f4 C/ `
[183, 84],
+ ]2 S3 ]& ?( E, x: v) R
[191, 80],
- s: @0 w v/ Z" e" O1 Q% Y+ Y
[155, 49],
8 x1 w# b' b# n& `" Z4 m$ t- }
[163, 59],
5 r o8 ?6 p9 d7 p
[180, 67],
) H) c7 g2 Z) s
[158, 54],
$ F/ g" q+ b/ F- g2 G A. o
[170, 67]])
" t; o: d) m( ~! P/ E" M4 r
y_train = ['male']*4 + ['female']*5 # 性别
( c8 `, M; O3 L+ g1 y2 R
/ B' q8 g9 I: O1 D
#绘制图像
9 z: \5 _7 ?2 b$ W$ e, \+ f9 N( x
plt.figure()
2 [2 T8 u' p0 S/ f- r5 [
plt.title('Human Height and Weights by Sex')
, I/ q! {& B4 s+ m& @
plt.xlabel('Height in cm')
/ w9 V9 C+ Y9 m- l
plt.ylabel('Weight in kg')
+ e2 ~8 x1 b: h$ g2 n2 ^4 V" Z
for i, x in enumerate(X_train):
1 {# [; ~5 p& z
plt.scatter(x[0],x[1],c='k',marker='x' if y_train
== 'male' else 'D')
! b- T8 Y8 v6 W, I' Q
plt.grid()
9 M, Y6 n1 |/ a C+ S
plt.show()
2 i7 h3 O- I& V
5 e" R! w' k/ ?9 Z4 ?! F) A" k2 R6 G
结果:
0 K) E2 ^% q) X8 u
* Q% I. Z& W& e4 f! i
- q: k1 S( n1 A) R& f
/ V- E1 M; \% [* Y
我们使用欧几里得距离公式来衡量距离:
8 `: _! ]6 B2 o4 |
7 l, ]" ]2 K1 W7 R. ~
8 Q Z/ B" @0 `" ?& ?' D& k
5 b1 [, C6 o( V$ l
6 p. k) W6 q0 B% Y' l. U$ I
: z6 d2 w2 U5 t$ \
我们设置参数K=3,来寻找3个距离最近的训练实例
+ r; O. w; a) \9 X" D% {% E4 s" {
* E, ^) b- [0 ]/ h. k: O2 |
下面代码实现K近邻算法进行分类:
1 K3 ~ R8 E7 t0 h- J
. T8 l q. R1 h. \# a; `
x = np.array([[155, 70]])
: ?+ u& v% a# v' y5 u! I
distances = np.sqrt(np.sum((X_train - x)**2, axis=1)) # 计算距离
' Q( x9 Y6 U/ w- t' o
; p) `; d6 X4 T9 O s
nearest_neighbor_indices = distances.argsort()[:3] # 找出前三个距离最小的下标
% n! s0 T( }3 [
nearest_neighbor_genders = np.take(y_train, nearest_neighbor_indices) # 得到下标对应的标签
+ A# N+ s! l. W4 v
! ]& l2 I; t+ n! A
from collections import Counter
2 Z! l9 V6 A! j Z5 U" E0 B
b = Counter(np.take(y_train, distances.argsort()[:3])) #得到三个结果标签中最频繁的标签得到结果female
. i5 R" a$ e# h; y
7 s1 a; r: m% H2 `
print(b.most_common(1)[0][0]) # female
7 k; Q$ i& m. ?: E* ^$ L" \& D9 v
因此,从上述代码可以得到K近邻算法进行分类就是找到离样本点最近的K个实例,再取K个实例的标签中出现次数最多的那个作为我们的结果。
2 g3 v" V+ X+ d" o
- v) e! H$ x' G6 q3 k" E
上述K近邻算法在scikit-learn中也有对应的函数:
4 k$ @ Q$ z, S& ^) k
7 G2 H l1 w8 b% h ?0 E0 ~
from sklearn.preprocessing import LabelBinarizer
' ?- ?, {" x$ N7 p+ U/ B- u' x% P T
from sklearn.neighbors import KNeighborsClassifier
$ J; n' d+ J8 U( H% t
9 a8 |" U- o# a/ z) b; u
lb = LabelBinarizer() # 创建将标签二值数值化的类实例
`; B+ f* W2 a4 U, Y; r2 ?% o: \
y_train_binarized = lb.fit_transform(y_train) # 将标签二值数值化
- _8 K9 S; R% u( g" X! D$ C: x
print(y_train_binarized)
2 u/ U+ K3 a+ `( ]+ W
9 ~1 ?: `0 `: Z1 d" n
K = 3
- E( m& w. e% t3 p8 `" i
clf = KNeighborsClassifier(n_neighbors=K) # 创建K近邻分类器实例
! U3 E# b, K+ z% C3 N! y
clf.fit(X_train, y_train_binarized.reshape(-1, 1)) # 对训练集进行训练
% T( H4 h! N! D4 S, @0 d) \$ p
prediction_binarized = clf.predict(np.array([155, 70]).reshape(1,-1))[0] # 对测试样本点进行预测
5 j9 h0 X* o$ y7 w' f6 }1 r& ?$ y, E
prediction_label = lb.inverse_transform(prediction_binarized) # 将预测结果从数字转换为标签
2 z* P2 V w! ~# ~/ o. z
print(prediction_label) # array(['female'], dtype='<U6')
1 s8 T5 H; h1 }0 d; |- N
KNN回归:
, ?+ H$ g* j( O& a
K近邻算法进行回归和K近邻思想一致,只不过在得到了K个邻居后,分类是取邻居中出现次数最多的那个,而回归是取其他的操作来预测输出值(比如取平均)
I7 s2 f/ d% ?. n" | E8 i
) V, o& h" ?* [. ~3 |3 T% G; i
对应的代码在scikit-learn中其实也很简单
/ j3 k% y4 e$ y( f1 R
& _5 l/ y/ E% }0 r4 E
from sklearn.neighbors import KNeighborsRegressor
+ v# h8 m5 z) ~$ K
K = 3
3 z4 d7 ? x7 g( g( d0 T- l5 n
clf = KNeighborsRegressor(n_neighbors=K)
2 E) f: S9 Y- q& y: g5 t
clf.fit(X_train, y_train)
. S" c7 p/ ` y) ]; V' F4 x
predictions = clf.predict(X_test)
: P4 `6 W* n6 V
特征缩放
: q7 r H5 Y4 ^9 H: w' M. x& T# p9 u
下面我们谈谈一个提升算法精确度的小细节。假设还是上面的数据,我们现在要做回归,给定身高和性别标签来预测体重。如果我们的训练数据集包含一个身高170cm的男性和身高160cm的女性。如果我们的测试集数据为身高为164cm的男性,你觉得其预测结果会接近170cm的男性还是身高160cm的女性呢?我们可能相信测试实例更接近男性实例,因为对预测体重来说,性别差异可能会比 6cm 的身高差距更重要。但是如果我们以毫米为单位表示身高,测试实例更接近于身高1600mm 的女性。如果我们以米为单位表示身高,测试实例更接近于身高 1.7m 的男性。(记住我们以欧几里得距离来衡量)
$ V+ p$ W0 Z0 j: H5 O% {
/ H6 ]7 k3 U" e& O3 i: g$ Y" X
因此,我们的特征缩放的作用就出来了(其实就相当于深度学习对数据集预处理中的Normalize)
6 G4 C) E8 \7 M+ d- n. f
4 R8 ^1 i( n: v& `1 }! {
将所有实例特征值减去均值来将其居中。其次将每个实例特征值除以特征的标准差对其进行缩放。均值为 0,方差为 1 的数据称为标准化数据。
# N% y+ F1 D2 J) n5 _8 ?
————————————————
" I* [7 E R# H4 t2 G+ O7 |) W
版权声明:本文为CSDN博主「王大队长」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
5 |+ ]: l/ _' \- s! _( I
原文链接:https://blog.csdn.net/qq_55621259/article/details/126695549
A5 @8 v+ l9 H& x" y
1 e* d% _# H: L+ v- S) ?
- u- i- G3 \. P
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5