机器学习之K近邻(KNN)

发布时间:2024年01月06日

谈谈机器学习之K近邻(KNN)

1 算法基本原理

1.1 KNN——K近邻原理
  • 通过计算距离来判断样本之间的相似程度

  • 距离越近两个样本就越相似, 就可以划归到一个类别中

    如该例子:唐人街探案属于什么类型的电影?

    序号电影名称搞笑镜头拥抱镜头打斗镜头电影类型
    1功夫熊猫39031喜剧片
    2叶问33265动作片
    3伦敦陷落2355动作片
    4代理情人9382爱情片
    5新步步惊心83417爱情片
    6谍影重重5257动作片
    7功夫熊猫39031喜剧片
    8美人鱼21175喜剧片
    9宝贝当家4529喜剧片
    10唐人街探案23317

根据欧式距离计算公式:在这里插入图片描述

可得伦敦陷落唐人街探案的距离为在这里插入图片描述

以此类推可以求得唐人街探案距离各电影的距离,因此可以得到下表:

序号电影名称搞笑镜头拥抱镜头打斗镜头电影类型距离K=5时
1功夫熊猫39031喜剧片21.47
2叶问33265动作片52.01
3伦敦陷落2355动作片43.42
4代理情人9382爱情片40.57
5新步步惊心83417爱情片34.44
6谍影重重5257动作片43.87
7功夫熊猫39031喜剧片21.47
8美人鱼21175喜剧片18.55
9宝贝当家4529喜剧片23.43
10唐人街探案23317——

? 若将K设置为5时,距离唐人街探案最近的5部电影便是功夫熊猫,新步步惊心,功夫熊猫,美人鱼,宝贝当家,根据投票原则,4票喜剧片,1票爱情片,所以唐人街探案属于喜剧片

1.2 基本流程
  • 计算当前样本和其它样本, 特征取值之间的距离(最常用的就是欧式距离), 对距离进行排序(从小到大)
  • 确定K值 : 通过离该样本最近的K个样本(欧式距离最小的K个)
    • 比如当K = 5时, 就选择离这个样本最近的5个样本
  • 通过这K个样本的类别确定当前样本的类别
    • 如果是分类问题, 投票, 少数服从多数
    • 如果是回归问题, 将K个样本的取值的平均值作为最终的预测结果

K 就是当前算法的一个超参数

  • 超参数是可以进行调整的
  • K的大小会影响到最终的结果
    • K越小 模型越复杂 容易受到数据中噪声的影响
    • K越大 模型越简单 受到数据分布的影响
    • 当K = 样本数量的时候, 模型结果是确定的结果

2 距离的度量方式

上面谈到了距离,具体有哪些距离计算公式来看看吧:

欧氏距离 在这里插入图片描述

曼哈顿距离 在这里插入图片描述

切比雪夫距离 在这里插入图片描述

闵可夫斯基距离 多种距离的总的表示公式

在这里插入图片描述

  • p = 1 曼哈顿
  • p = 2 欧氏距离
  • p = ∞ 切比雪夫距离
  • sklearn KNN API 默认使用的是欧式距离

3 API的使用

分类问题:

# 1.工具包
from sklearn.neighbors import KNeighborsClassifier,KNeighborsRegressor
# from sklearn.neighbors import KNeighborsRegressor

# 2.数据(特征工程)
# 分类
x = [[0,2,3],[1,3,4],[3,5,6],[4,7,8],[2,3,4]]
y = [0,0,1,1,0]

# 创建算法对象  K近邻的分类器
knn = KNeighborsClassifier(n_neighbors=1)
# 算法模型对象 调用fit 模型训练
knn.fit(x,y) # X 训练集特征值 y 训练集目标值
# 使用训练好的模型进行预测
knn.predict([[4,4,5]])

回归问题:

# 准备数据  x 特征值
x = [[0,1,2],[1,2,3],[2,3,4],[3,4,5]]
# y 目标值
y = [0.1,0.2,0.3,0.4]
# 创建K近邻的回归器
knn = KNeighborsRegressor(n_neighbors=2)
# 模型训练 对于KNN来说, 就是把所有样本保存起来
knn.fit(x,y)
# 利用模型输出预测结果
knn.predict([[4,4,5]])

SKlearn 的API 都有固定的套路

  • 创建算法模型对象
  • fit 模型训练
  • predict 使用训练好的模型进行预测

模型训练的时候, 使用的数据, 有几个特征, 是什么样的维度, 在predict的时候传入的数据需要有相同的维度

4 鸢尾花案例

? 在正式开始该案例之前,为了让模型有一个好的应用效果,先了解一个特征工程中的概念。

4.1 归一化/标准化

是特征工程中特征预处理的一个环节

应用场景:

  • 涉及多个特征一起进行计算, 比如计算欧式距离
  • 特征的取值范围, 差异较大 (量纲不统一)

归一化/标准化 可以把量纲不统一的特征, 缩放到同一取值范围内

  • 归一化 在这里插入图片描述

  • 标准化 在这里插入图片描述

需要注意的是

  • 归一化会受到数据中异常值的影响, 当对数据质量没有把握的时候, 可以直接使用标准化
# 如果数据中有特别大的取值/特别小的取值     收入  10000小目标      0.00001个小目标
from sklearn.preprocessing import MinMaxScaler
x = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]
# 创建一个Scaler对象
scaler = MinMaxScaler()
# fit 就是在计算每一列特征的最大值和最小值, 并保存到scaler对象中
scaler.fit(x)
# Transform 变化, 利用上一步计算出来的 最大最小值, 作用到原始数据上, 得到缩放之后的结果
scaler.transform(x)

标准化

# 标准化没有固定取值范围, 基本上会在 -10 10
from sklearn.preprocessing import StandardScaler
x = [[90, 2, 10, 40], [60, 4, 15, 45], [75, 3, 13, 46]]
# 创建一个Scaler对象
scaler = StandardScaler()
# fit 就是在计算每一列特征的均值和方差
scaler.fit(x)
# Transform 变化, 利用上一步计算出来的 最大最小值, 作用到原始数据上, 得到缩放之后的结果
scaler.transform(x)
4.2 数据加载
iris_data = load_iris()
iris.feature_names # 特征名字

[‘sepal length (cm)’,
‘sepal width (cm)’,
‘petal length (cm)’,
‘petal width (cm)’]

iris.target_names # 目标值名称

[‘setosa’ ‘versicolor’ ‘virginica’]

X,y = load_iris(return_X_y=True) # 如果加上return_X_y=True 只会返回特征值和目标值
4.3 特征工程
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# X 数据集的特征, y 数据集的目标, test_size 测试集的比例  random_state 随机数种子, 写死了一个随机数种子每次得到的数据集划分结果都是一样的
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.2,random_state=42)
# 特征工程
scaler = StandardScaler() # 标准化
# 训练集 测试集 要不要都做标准化  都要做
scaler.fit(X_train) # 计算均值 方差  120
X_train_scaled = scaler.transform(X_train) # 做标准化计算
# scaler.fit(X_test) # 计算均值 方差   30 
X_test_scaled = scaler.transform(X_test) # 做标准化计算

特征工程需要注意

  • 训练集 fit transform
  • 测试集 直接transform
4.4 模型训练
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train_scaled,y_train) # 使用标准化之后的特征值, 进行模型训练
KNN 特点, 不需要训练, 数据就是模型本身, 数据发生了变化, 模型就发生了变化

fit的时候就是把 X_train_scaled 和 y_train保存下来

4.5 模型评估
y_train_pred = knn.predict(X_train_scaled) # 用训练好的模型 对训练集进行分类
y_test_pred = knn.predict(X_test_scaled)  # 用训练好的模型 对测试集进行分类
from sklearn.metrics import accuracy_score
accuracy_score(y_train,y_train_pred) # 准确率  利用模型输出的结果和 真实标签进行比较, 如果两者一致说明 模型分类正确, 如果不一致说明分类错误
#准确率 计算的是 分类正确样本的比例
accuracy_score(y_test,y_test_pred)

accuracy_score 准确率 分类问题的评价方法之一

4.6 数据可视化
 # 对数据做简单的可视化
import pandas as pd
iris_df = pd.DataFrame(iris.data,columns=iris.feature_names)
iris_df['label'] = iris.target
iris_df

import seaborn as sns
# data 要绘图的数据, x x轴数据在df中的列名 y = y轴数据在df中的列名   hue 传入类别型取值的特征列, 会自动用不同颜色来表示, fit_reg=默认会拟合一个回归直线
sns.lmplot(data=iris_df,x='sepal length (cm)',y='petal width (cm)',fit_reg=False,hue ='label')
# hue = 'label' 用标签列, 对数据点进行区分展示, 3种不同的鸢尾花分别用不同的颜色显示

在这里插入图片描述

5 交叉验证和网格搜索(提升自动化)

5.1 交叉验证和网格搜索的概念

可以使用交叉验证和网格搜索来做超参数的调整

  • 超参数 就是创建算法模型对象的时候, 需要人为传入的参数
    • 对于KNN来说, 可以调整的参数包括
      • K 邻居的个数
      • P 距离测量方式
      • weights 权重调整方法

网格搜索

  • 把所有要尝试的参数组合, 都遍历一圈, 使用数据来训练对应模型, 通过验证集表现来找到最佳的参数组合

交叉验证

可以把训练数据进一步划分成训练集和验证集

  • cv = 4 把训练集划分成4份, 3份训练1份用来验证(并且使每一份数据都会作一次验证集)

把网格搜索和交叉验证结合起来, 就是在不同的数据中(训练集和验证集), 来尝试不同的参数组合

  • 每一个参数组合, 都会计算cv次, 每次的评估指标计算平均值, 通过指标平均值来判断哪组参数最好

5.2 交叉验证和网格搜索的API

knn_estimator = KNeighborsClassifier(n_neighbors=3) # 创建K近邻模型对象
param_grid_ = {'n_neighbors':[2,3,4,5,6],'p':[1,2],'weights':['uniform','distance']}# 创建网格搜索的超参数空间
grid_estimator = GridSearchCV(estimator=knn_estimator,param_grid=param_grid_,cv=4)

n_neighbors KNN k的取值

p 1,2 1 曼哈顿距离, 2 欧氏距离

weights 权重 投票时的权重

  • 默认uniform 平权投票, 所有的样本权重都一样
  • distance 加权投票 考虑距离的倒数作为权重
grid_estimator.fit(x_train_scaled,y_train) # 使用标准化之后的 训练集数据进行模型训练
y_train_pred = grid_estimator.predict(x_train_scaled) # 使用训练好的模型, 对训练集数据进行分类
print('训练集:',accuracy_score(y_train,y_train_pred))
y_test_pred = grid_estimator.predict(x_test_scaled) # 使用训练好的模型, 对测试集数据进行分类
print('测试集:',accuracy_score(y_test,y_test_pred))

grid_estimator.cv_results_

  • 记录了交叉验证网格搜索的全部过程, 每组验证集的评价结果
grid_estimator.best_params_ # 最佳的参数组合, 如果有并列的情况, 默认返回的是以一个第一名对应的参数组合
grid_estimator.best_score_  # 最佳分数 交叉验证时的最好的平均分数

red = grid_estimator.predict(x_test_scaled) # 使用训练好的模型, 对测试集数据进行分类
print(‘测试集:’,accuracy_score(y_test,y_test_pred))


grid_estimator.cv_results_ 

- 记录了交叉验证网格搜索的全部过程, 每组验证集的评价结果

grid_estimator.best_params_ # 最佳的参数组合, 如果有并列的情况, 默认返回的是以一个第一名对应的参数组合
grid_estimator.best_score_ # 最佳分数 交叉验证时的最好的平均分数

希望可以帮到大家,不要忘记点赞收藏欧!

文章来源:https://blog.csdn.net/weixin_67656334/article/details/135419724
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。