网格搜索(调参)与数据预处理

网格搜索

Grid Search

网格搜索是一种调参手段;穷举搜索:在所有候选的参数选择中,通过循环遍历,尝试每一种可能性,表现最好的参数就是最终的结果。其原理就像是在数组里找最大值。(为什么叫网格搜索?以有两个参数的模型为例,参数a有3种可能,参数b有4种可能,把所有可能性列出来,可以表示成一个3*4的表格,其中每个cell就是一个网格,循环过程就像是在每个网格里遍历、搜索,所以叫grid search)

本章我使用的还是digits数据集,调用方法接上一章。

#网格搜索,具体的格式可以上http://scikit-learn.org自行寻找。
# generates candidates
grid_param = [
    {
        'weights':['uniform'],
        'n_neighbors':[i for i in range(1,11)]
    },
    {
        'weights':['distance'],
        'p':[i for i in range(1,6)],
        'n_neighbors':[i for i in range(1,11)]
    }
]
# 先new一个默认的Classifier对象
knn_clf = KNeighborsClassifier()

# 调用GridSearchCV创建网格搜索对象,传入参数为Classifier对象以及参数列表
from sklearn.model_selection import GridSearchCV
grid_clf = GridSearchCV(knn_clf,grid_param)

# 调用fit方法执行网格搜索
grid_clf.fit(X_train,y_train)

 网格搜索(调参)与数据预处理

# 不是用户传入的参数,而是根据用户传入的参数计算出来的结果,以_结尾
# 最好的评估结果,返回的是KNeighborsClassifier对象
grid_clf.best_estimator_

网格搜索(调参)与数据预处理 # 最好的分数
grid_clf.best_score_

网格搜索(调参)与数据预处理

# 最好的参数
grid_clf.best_params_

网格搜索(调参)与数据预处理

#使用最好的分类器去求测试数据精度。

knn_clf_best = grid_clf.best_estimator_
knn_clf_best.score(X_test,y_test)

网格搜索(调参)与数据预处理

%%time
# n_jobs 多线程并行处理,占用几个核,-1为使用所有的核
# verbose 是否打印搜索信息,传入值越大,输出信息越详细
grid_clf = GridSearchCV(knn_clf,grid_param,n_jobs=-1,verbose=2)
grid_clf.fit(X_train,y_train)

网格搜索(调参)与数据预处理

 数据归一化:

样本间的距离被一个字段所主导

网格搜索(调参)与数据预处理

 

网格搜索(调参)与数据预处理

解决方案 :将所有的数据映射到同一尺度

最值归一化:把所有数据映射到0-1之间

网格搜索(调参)与数据预处理

1.将这个数据映射到0~Xmax-Xmin 之间
2.然后对于每个x相比于整个范围所占的比例

适用于分布有明显边界的情况;受outlier影响较大

均值方差归一化 standardization

把所有数据归一到均值为0方差为1的分布中

适用于数据分布没有明显边界;有可能存在极端情况值

网格搜索(调参)与数据预处理

优点(相对于最值归一化):即使原数据集中有极端值,归一化有的数据集,依然满足均值为0方差为1,不会形成一个有偏的数据;

对测试数据集如何归一化?

 

网格搜索(调参)与数据预处理

在scikit-learn中使用Scaler

网格搜索(调参)与数据预处理

 Scikit-learn 中的Scaler:

import numpy as np
from sklearn import datasets

iris = datasets.load_iris()
X = iris.data
y = iris.target

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

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit(X_train)

scaler.mean_

scaler.scale_

X_train = scaler.transform(X_train)
X_train

from sklearn.neighbors import KNeighborsClassifier
knn_clf = KNeighborsClassifier(n_neighbors=3)

knn_clf.fit(X_train,y_train)

knn_clf.score(X_test,y_test)

网格搜索(调参)与数据预处理

网格搜索(调参)与数据预处理

网格搜索(调参)与数据预处理

网格搜索(调参)与数据预处理

让我们来实现一下自己的StandardScaler :

import  numpy as np
class StandardScaler:

    def __init__(self):
        self.mean_ = None
        self.scale_ = None

    def fit(self,X):
        """根据训练数据集X获得数据的均值和方差"""
        assert X.ndim == 2 ,"the dimension of X must be 2"

        self.mean_ =np.array([np.mean(X[:,i]) for i in range(X.shape[1])])
        self.scale_ = np.array([np.std(X[:,i]) for i in range(X.shape[1])])

        return self

    def transform(self,X):
        """将X根据当前StandardScaler进行均值方差归一化处理"""
        assert X.ndim == 2, "the dimension of X must be 2"
        assert self.mean_ is not None and self.scale_ is not None,\
            "must fit before transform!"
        assert X.shape[1] == len(self.mean_),\
            "the feature number of X must be equal to mean_ and std_"
        resX =np.empty(shape=X.shape,dtype=float)

        for col in range(X.shape[1]):
            resX[:,col] = (X[:,col] - self.mean_[col]) / self.scale_[col]
        return resX

 1.将数据集分成训练数据集和测试数据集
2.将训练数据集进行归一化
3.使用训练数据集的均值和方差将测试数据集归一化
4.使用训练数集训练出模型
5.使用归一化后的测试数据集测试分类的准确度(accuracy)
6.使用网格搜索寻找最好的超参数,然后回到1-5

 

ps:为什么要用训练集的均值与方差去对测试数据集进行归一化呢?

  • 原因1:真实的环境中,数据会源源不断输出进模型,无法求取均值和方差的;
  • 原因2:训练数据集是模拟真实环境中的数据,不能直接使用自身的均值和方差;
  • 原因3:真实环境中,无法对单个数据进行归一化;

网格搜索(调参)与数据预处理