问题:发生了过拟合成不自知

解决方法:train test split

训练数据集:训练模型
测试数据集:调整超参数
问题:针对特定测试数据集过拟合?

解决方法:训练 - 验证 - 测试

训练数据集:训练模型
验证数据集:调整超参数
测试数据集:不参数模型创建,作为衡量最终模型性能的数据集
问题:随机?一旦验证数据集有异常数据,就会导致模型不准确

解决方法:交叉验证

代码实现

import numpy as np
from sklearn import datasets

digits = datasets.load_digits()
X = digits.data
y = digits.target

测试train_test_split

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=666)

from sklearn.neighbors import KNeighborsClassifier

best_score, best_k, best_p = 0,0,0
for k in range(2, 11):
    for p in range(1, 6):
        knn_clf = KNeighborsClassifier(weights="distance", n_neighbors=k, p=p)
        knn_clf.fit(X_train, y_train)
        score = knn_clf.score(X_test, y_test)
        if score > best_score:
            best_score, best_k, best_p = score, k, p

print("best k = ", best_k)
print("best p = ", best_p)
print("best score = ", best_score)

输出结果:
best k = 3
best p = 4
best score = 0.9860917941585535

使用交叉验证

from sklearn.model_selection import cross_val_score

knn_clf = KNeighborsClassifier()
cross_val_score(knn_clf, X_train, y_train)

输出结果:
array([0.98895028, 0.97777778, 0.96629213])

from sklearn.neighbors import KNeighborsClassifier

best_score, best_k, best_p = 0,0,0
for k in range(2, 11):
    for p in range(1, 6):
        knn_clf = KNeighborsClassifier(weights="distance", n_neighbors=k, p=p, cv=3)
        scores = cross_val_score(knn_clf, X_train, y_train)
        score = np.min(scores)
        if score > best_score:
            best_score, best_k, best_p = score, k, p

print("best k = ", best_k)
print("best p = ", best_p)
print("best score = ", best_score)

输出结果:
best k = 2
best p = 2
best score = 0.9823599874006478

train_test_split和交叉验证结果对比:
两种方法得到的best_k和best_p,通常认为使用交叉验证得到参数更可靠。
因为方法一得到的结果很有可能只是过拟合了那一组测试数据。
方法二的分数低于方法一,因为它没有过拟合某一组数据。

best_knn_clf = KNeighborsClassifier(weights="distance", n_neighbors=2, p=2)
best_knn_clf.fit(X_train, y_train)
best_knn_clf.score(X_test, y_test)

输出结果:0.980528511821975

Note:这个算法最终的分类准确度不是上面的0.9823,而是这里的0.9805

回顾网格搜索

from sklearn.model_selection import GridSearchCV

param_grid = [
    {   
        'weights':['distance'],
        'n_neighbors': [i for i in range(2, 11)],
        'p': [i for i in range(1, 6)]
    }
]

from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier()
grid_search = GridSearchCV(knn_clf, param_grid, cv=3)
grid_search.fit(X_train, y_train)

输入:grid_search.best_score_
输出:0.9823747680890538

输入:grid_search.best_params_
输出:{'n_neighbors': 2, 'p': 2, 'weights': 'distance'}

输入:

best_knn_clf = grid_search.best_estimator_
best_knn_clf.score(X_test, y_test)

输出:0.980528511821975

使用网络搜索与使用交叉验证得到的结果相同。