【机器学习】以KNN为例的交叉验证 网格搜索
KNN
K-Nearest Neighbors 简称为KNN,根据k个最近的邻居的类别判断当前样本的类别,k一般取奇数。
k个邻居中哪种类别的样本多,就判断这个为这个类别
-
距离判断
knn首先要判断两个样本之间的距离,距离有多种表示方式
- 欧氏距离
- 生活中常用的距离公式,二维空间中的两点 ( x 1 , y 1 ) ( x 2 , y 2 ) (x_1,y_1)(x_2,y_2) (x1,y1)(x2,y2)距离表示为 ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 \sqrt{\left(x_{1}-x_{2}\right)^{2}+\left(y_{1}-y_{2}\right)^{2}} (x1−x2)2+(y1−y2)2
- 多个维度差距的综合
- 曼哈顿距离
- 二维空间中的两点 ( x 1 , y 1 ) ( x 2 , y 2 ) (x_1,y_1)(x_2,y_2) (x1,y1)(x2,y2)距离表示为 ( x 1 − x 2 ) + ( y 1 − y 2 ) (x_1-x_2)+(y_1-y_2) (x1−x2)+(y1−y2)
- 可以理解为是每个维度上的距离之和
- 欧氏距离
-
缺点
对于高维数据,并不合适。且当数据量很大计算效率会很低
维度变大,数据变得稀疏,距离会很远
-
class sklearn.neighbors.KNeighborsClassifier(n_neighbors=5, algorithm='auto')n_neighborsn的大小 邻居的数量- 创建之后使用fit训练,拟合数据
- predict进行预测
- score准确率
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifierx,y = load_iris(return_X_y=True) # 加载数据集 x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,shuffle=True) # 数据集划分并随机打乱 model = KNeighborsClassifier(n_neighbors=7) # 创建预估器 model.fit(x_train,y_train) # 拟合数据 进行训练 y_pre = model.predict(x_test) # 进行预测 print(sum(y_pre==y_test)/y_test.shape[0]) # 进行判断,正确的累加, 求准确率 model.score(x_test,y_test)# 准确率''' 0.9777777777777777 0.9777777777777777 '''
模型的选择和调优(以KNN为例)
- 交叉验证
-
保留交叉验证
- 把数据集根据比率随机划分为训练集和测试集
from sklearn.model_selection import train_test_splitx_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,shuffle=True) # 数据集划分并随机打乱
-
K折交叉验证
- 将数据随机划分为多个部分,每个部分就是一折
- 每一折作为测试集,其他作为训练集,每一折都会被用于训练
from sklearn.model_selection import KFoldkfold = KFold() # K折交叉验证参数n_splits默认值为5,划分为5折index = kfold.split(x,y) # 返回索引
-
分层k折交叉验证
- 保证每一折都是原始数据的样本比例
sklearn.neighbors.StratifiedKFold(n_splits=5, shuffle=True, random_state=42)- 同样返回索引
# 交叉验证
from sklearn.datasets import load_wine
from sklearn.model_selection import KFold,StratifiedKFold
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
x,y = load_wine(return_X_y=True) # 获得数据,以data,target 返回kfold = KFold() # K折交叉验证
index = kfold.split(x,y) # 返回索引# S_kfold = StratifiedKFold() # 分层交叉验证
# index = S_kfold.split(x,y)KNN_class = KNeighborsClassifier(n_neighbors=7) # KNN
scaler = StandardScaler() # 标准化
score_list = []
for index_train,index_test in index:x_train = x[index_train]y_train = y[index_train]x_test = x[index_test]y_test = y[index_test]x_train = scaler.fit_transform(x_train) # 标准化x_test = scaler.transform(x_test)KNN_class.fit(x_train,y_train)score = KNN_class.score(x_test,y_test) # 获得准确率score_list.append(score)print(sum(score_list)/len(score_list)) # 获得几次的平均准确率
- 超参数搜索(网格搜索)
实例化预估器时,预估器会传入一些人为规定的参数如n_neighbors, 这样的参数被称为超参数。
通过网格搜索,可以找到训练效果最好的超参数
sklearn.model_selection.GridSearchCV(estimator, param_grid)estimator需要进行优化的预估器,模型param_grid超参数字典 字典的键是参数列表
GridSearchCV这个类有这样的一些属性
best_params_ 最佳参数
best_score_ 在训练集中的准确率
best_estimator_ 最佳估计器
cv_results_ 交叉验证过程描述
best_index_最佳k在列表中的下标
# 超参数搜索 网格搜索
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split,GridSearchCV # 网格搜索
import joblib
'''
GridSearchCV
best_params_ 最佳参数
best_score_ 在训练集中的准确率
best_estimator_ 最佳估计器
cv_results_ 交叉验证过程描述
best_index_最佳k在列表中的下标
'''x,y = load_breast_cancer(return_X_y=True)
scaler = StandardScaler()
x = scaler.fit_transform(x) # 标准化# 数据集划分
train_x,test_x,tain_y,test_y = train_test_split(x,y,shuffle=True,random_state=1,test_size=0.3)KNN_classfier = KNeighborsClassifier()n_dic = {'n_neighbors':[3,5,7,9]
}model = GridSearchCV(KNN_classfier,param_grid=n_dic)
model.fit(x_train,y_train)
print(model.score(x_test,y_test))
print(model.best_params_)
print('*'*20)
print(model.best_score_)
print('*'*20)
print(model.best_estimator_)
print(type(model))
'''
0.9142857142857143
{'n_neighbors': 3}
********************
0.9514778325123153
********************
KNeighborsClassifier(n_neighbors=3)
<class 'sklearn.model_selection._search.GridSearchCV'>
'''
模型的保存和加载
使用joblib中的两个函数
joblib.dump(model.best_estimator_,'./best_KNN_cancer.plk') # 模型保存 保存模型结构和参数
model = joblib.load('./best_KNN_cancer.plk') # 模型加载
print(type(model))
'''
model = joblib.load('./KNN-7.plk')
print(type(model))
'''
