KNN与交叉验证(基础知识 + 实战代码)

KNN

近朱者赤,近墨者黑

  • 既可以解决分类问题,也可以解决回归问题

    • 回归问题:求出k个待测样本的平均值作为预测样本最终的预测值

1 样本距离公式

  • 欧拉距离
    两个样本对应特征值之差的平方的累加和再开根号
    欧拉距离公式

  • 哈曼顿距离
    两个样本对应特征值之差的累加和
    哈曼顿距离公式

  • 明可夫斯基距离(p是一个超参数)
    明可夫斯基距离公式

    超参数:p是在计算前就已经设定好的数

2 特征标准化距离

避免了样本间距离一直被某些数值较大的特征所主导的问题。

  • z-score标准化
    z-score公式

    • s:标准差
    • xmean:特征值的平均值

sklearn.preprocessing.StandardScaler

实战:

fit:只对样本训练集进行

交叉验证

  • 将数据集切分成三部分:训练集、验证集、测试集
    • 训练集:训练模型
    • 验证集:用于模型的选择
    • 测试集:最终评估

1 K折交叉验证

  1. 切分训练集:将训练数据集切分为k互不相交大小相同的子集
  2. 训练模型:用其中k-1个子集
  3. 验证模型:用余下的子集
  4. 将这一过程对可能的k中选择重复进行(这一过程使用的是同一组超参数
  5. 计算交叉验证误差:计算k次的预测误差并对其求平均值。
    K折交叉验证

在这个过程中要多试几组超参数,最后选择成绩最好的去测试数据。

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier # KNN分类器

# 数据加载,展示图像
digits = datasets.load_digits()
X = digits.data #样本特征
y = digits.target #样本标签

# 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=666)

# 交叉验证开始
from sklearn.model_selection import cross_val_score

best_k, best_p, best_score = 0, 0, 0
for k in range(2, 11): # 外层搜索k
    for p in range(1, 6): # 内层搜索p
        knn = KNeighborsClassifier(weights="distance", n_neighbors=k, p=p)
        scores = cross_val_score(knn, X_train, y_train, cv=3, scoring='accuracy') # 3折交叉验证
        score = np.mean(scores) # 当前这一组超参数在验证集上的平均得分
        if score > best_score:
            best_k, best_p, best_score = k, p, score

print("best_k=",best_k)
print("best_p=",best_p)
print("验证集上最好成绩:best_score=",best_score)


# 使用调好的超参数进行训练与测试
best_knn = KNeighborsClassifier(weights="distance", n_neighbors=2, p=2)
best_knn.fit(X_train, y_train)
best_knn.score(X_test, y_test) # 测试集上最终的分数

2 留一交叉验证

  • 留一法:是K折交叉验证的特殊情形,即K=N,这里N是给定训练数据集的容量。

  • 留一法不受随机样本划分方式的影响,最接近模型真正的性能指标。因为N个样本只有唯一的方式划分为N个子集——每个子集包含一个样本。

  • 缺点:计算量巨大。经常在科研中使用。

3 实战:网格搜索调参

  • 网格搜索?
    • 网格搜索可以实现自动调参并返回最佳的参数组合
    • 网格搜索,搜索的是参数,即在指定的参数范围内,依次调整参数,利用调整的参数训练学习器
    • 底层还是用到了交叉搜索
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier

# 加载数据集
digits = datasets.load_digits()
X = digits.data # 样本特征
y = digits.target # 样本标签

# 拆分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=666)

# 网格搜索
from sklearn.model_selection import GridSearchCV

# 组装待搜索的超参数
param_grid = [
    {
        "weights":["uniform"],
        "n_neighbors":[i for i in range(1,11)],
    },
    {
        "weights":["distance"],
        "n_neighbors":[i for i in range(1,11)],
        "p":[i for i in range(1,6)]
    }
]

knn = KNeighborsClassifier()
grid_search = GridSearchCV(knn,param_grid,cv=3,n_jobs=1) # cv=3表示3折交叉验证 n_jobs=-1表示使用全部核
grid_search.fit(X_train,y_train) # 开始搜索, 搜索最佳超参数(很耗时!)

# print(grid_search.best_params_) # 输出最优超参数组合
# print(grid_search.best_score_) # 输出验证最佳成绩

# 携带最佳超参数组合的KNeighborsClassifier对象
best_knn = grid_search.best_estimator_
best_knn.fit(X_train, y_train) # 使用最佳超参数组合的分类器进行拟合训练
print("在测试集上最后总评估效果:",best_knn.score(X_test, y_test))


  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值