目录
一、KNN模型
KNN(K近邻)模型,不会预先生成一个分类或预测模型,用于新样本的预测,而是将模型的构建与未知数据的预测同时进行。
该算法对数据的分布特征没有任何要求。
1 核心思想
比较已知y值的样本与未知y值样本的相似度,然后寻找最相似的k个样本用作未知样本的预测。
算法主要任务:
- 确定最近邻的个数k值;
- 用于度量样本间相似性的指标。
2 k值的选择
k值的影响:
- k值过于偏小,可能会导致模型的过拟合;
- 反之,又可能会使模型进入欠拟合状态
为了获得最佳的k值,可以考虑三种解决方案:
- 第一种,设置k近邻样本的投票权重。通常可以将权重设置为距离的倒数;
- 第二种,采用多重交叉验证法,该方法是目前比较流行的方案,其核心就是将k取不同的值,然后在每种值下执行m重的交叉验证,最后选出平均误差最小的k值;
- 第三种,结合前两种方法,选出理想的k值。
3 相似度的度量方法
- 欧氏距离
- 曼哈顿距离
- 余弦相似度
- 杰卡德相似系数
3.1 欧氏距离
该距离度量的是两点之间的直线距离。公式如下(针对点A( x 1 , x 2 , . . . , x n ) x_1,x_2,...,x_n) x1,x2,...,xn)、B( y 1 , y 2 , . . . , y n y_1,y_2,...,y_n y1,y2,...,yn)):
d A , B = ( y 1 − x 1 ) 2 + ( y 2 − x 2 ) 2 + . . . + ( y n − x n ) 2 d_{A,B}=\sqrt{(y_1-x_1)^2+(y_2-x_2)^2+...+(y_n-x_n)^2} dA,B=(y1−x1)2+(y2−x2)2+...+(yn−xn)2
3.2 曼哈顿距离
该距离也称为“曼哈顿街区距离”,度量的是两点在轴上的相对距离总和。公式如下(针对点A( x 1 , x 2 , . . . , x n ) x_1,x_2,...,x_n) x1,x2,...,xn)、B( y 1 , y 2 , . . . , y n y_1,y_2,...,y_n y1,y2,...,yn)):
d A , B = ∣ y 1 − x 1 ∣ + ∣ y 2 − x 2 ∣ + . . . + ∣ y n − x n ∣ d_{A,B}=|y_1-x_1|+|y_2-x_2|+...+|y_n-x_n| dA,B=∣y1−x1∣+∣y2−x2∣+...+∣yn−xn∣
3.3 余弦相似度
该相似度其实就是计算两点所构成向量夹角的余弦值,夹角越小,则余弦值越接近于1,进而能够说明两点之间越相似。公式如下(针对点A( x 1 , x 2 , . . . , x n ) x_1,x_2,...,x_n) x1,x2,...,xn)、B( y 1 , y 2 , . . . , y n y_1,y_2,...,y_n y1,y2,...,yn)):
S
i
m
i
l
a
r
i
t
y
A
,
B
=
cos
θ
=
A
⃗
⋅
B
⃗
∣
∣
A
⃗
∣
∣
∣
∣
B
⃗
∣
∣
Similarity_{A,B}=\cos \theta=\frac{\vec{A}·\vec{B}}{\mid\mid \vec{A}\mid \mid\mid\mid\vec{B}\mid\mid}
SimilarityA,B=cosθ=∣∣A∣∣∣∣B∣∣A⋅B
其中,点·代表两个向量之间的内积,符号‖‖代表向量的模,即l2正则。
3.4 杰卡德相似系数
该相似系数与余弦相似度经常被用于推荐算法,计算用户之间的相似性。 公式如下:
J
(
A
,
B
)
=
∣
A
⋂
B
∣
∣
A
⋃
B
∣
J(A,B)=\frac{\mid A\bigcap B\mid}{\mid A \bigcup B\mid}
J(A,B)=∣A⋃B∣∣A⋂B∣
其中,|A∩B|表示两个用户所购买相同商品的数量,|A∪B|代表两个用户购买所有产品的数量。
使用距离方法来度量样本间的相似性时,必须注意两点:
- 一个是所有变量的数值化;
- 另一个是防止数值变量的量纲影响,必须采用数据的标准化方法对其归一化,使得所有变量的数值具有可比性。
4 近邻样本的搜寻方法
近邻样本的搜寻方法:
- 暴力搜寻法:需要全表扫描,只能适合小样本的数据集
- KD树搜寻法:不需要全表扫描
- 球树搜寻法:不需要全表扫描
4.1 KD树搜寻法
K-Dimension Tree,K表示训练集中包含的变量个数。其最大的搜寻特点:先利用所有已知类别的样本点构造一棵树模型,然后将未知类别的测试集应用在树模型上,实现最终的预测功能。
KD树搜寻法的两个重要步骤:
- KD树的构造
- KD树的搜寻
缺点:该方法在搜寻分布不均匀的数据集时,效率会下降很多。
4.2 球树搜寻法
球树搜寻法能够解决KD树的缺陷,是因为球树将KD树中的超矩形体换成了超球体,没有了“角”,就不容易产生模棱两可的区域。
优缺点:与KD树的思想非常相似,所不同的是,球树的最优搜寻路径复杂度提高了,但是可以避免很多无谓样本点的搜寻。
球树搜寻法的两个重要步骤:
- 球树的构造
- 球树的搜寻
5 KNN模型实例
Python中的sklearn的子模块neighbors中有关KNN算法的类:KNeighborsClassifier类(分类)和KNeighborsRegressor类(预测)。
KNeighborsClassifier(
n_neighbors=5,
weights=‘uniform’, # ‘uniform’,表示所有近邻样本的投票权重一样;如果为’distance’,则表示投票权重与距离成反比
algorithm=‘auto’, #‘ball_tree’,则表示使用球树搜寻法; ‘kd_tree’,则表示使用KD树搜寻法; ‘brute’,则表示使用暴力搜寻法
leaf_size=30, # 用于指定球树或KD树叶子节点所包含的最小样本量
p=2,
metric=‘minkowski’, # 用于指定距离的度量指标
metric_params=None,
n_jobs=None,
**kwargs,
)
以下以分类问题为例:
# 导入第三方库
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
from sklearn import metrics
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score # 交叉验证
# 读入数据
kdata = pd.read_excel(r'Knowledge.xlsx')
# --------------------构造训练集和测试集------------------------
x_columns = kdata.columns[:-1]
y_column = kdata.columns[-1]
X_train,X_test,y_train,y_test = train_test_split(kdata[x_columns],
kdata[y_column],
test_size=0.25,
random_state=111)
#-------------------使用十折交叉验证寻找最优k值-----------------
# 设置待测试的不同k值
K = np.arange(1,np.int(np.log2(kdata.shape[0])))
accuracy = [] # 用于存储不同k值10折后的模型平均准确率
for k in K:
# 使用十折交叉验证比对不同k值的预测准确率
cv_result = cross_val_score(KNeighborsClassifier(n_neighbors=k,
weights='distance'),
X_train,y_train,cv=10,scoring='accuracy')
accuracy.append(cv_result.mean())
# -------------------可视化准确率结果-----------------------------
# 挑选出准确率最大值对应的下标
k_max_index = np.array(accuracy).argmax()
# 中文和负号的正常显示
plt.rcParams['font.sans-serif']=['Microsoft YaHei']
plt.rcParams['axes.unicode_minus']= False
plt.plot(K,accuracy)
plt.scatter(K,accuracy)
plt.text(K[k_max_index],accuracy[k_max_index],'最佳k值为{}'.format(K[k_max_index]))
plt.show()
# ---------------- 根据最佳k值 构建模型-----------------------
model = KNeighborsClassifier(n_neighbors=K[k_max_index],weights='distance')
model.fit(X_train,y_train)
y_pre = model.predict(X_test)
# 构建混淆矩阵
cross_matrix = pd.crosstab(y_pre,y_test)
# 将混淆矩阵构造成数据框,并加上字段名和行名称,用于行或列的含义说明
cross_matrix = pd.DataFrame(cross_matrix)
# 绘制热力图
sns.heatmap(cross_matrix, annot = True,cmap = 'GnBu')
# 添加x轴和y轴的标签
plt.xlabel(' 真实值')
plt.ylabel(' 预测值')
# 图形显示
plt.show()
# ----------------- 模型评估报告 -------------------------
print(metrics.classification_report(y_test,y_pre))
类别 | precision | recall | f1-score | support |
---|---|---|---|---|
High | 1.00 | 0.96 | 0.98 | 27 |
Low | 0.82 | 1.00 | 0.90 | 33 |
Middle | 0.96 | 0.86 | 0.91 | 29 |
Very Low | 1.00 | 0.75 | 0.86 | 12 |
accuracy | 0.92 | 101 | ||
macro avg | 0.95 | 0.89 | 0.91 | 101 |
weighted avg | 0.93 | 0.92 | 0.92 | 101 |