07-scikit-learn中的Scaler

scikit-learn中的Scaler

  在上一篇博客中介绍了将数据归一化的两种方式,最值归一化和均值方差归一化。但是具体的将这种归一化的方式用在我们的机器学习过程中的时候,有一个很重要的注意事项。

  对于我们的原始数据集,我们将其划分为训练数据集和测试数据集。如果我们要使用归一化的数据来训练我们的模型的话,显然我们需要对训练数据集进行归一化处理。比如说,我们使用均值方差归一化的处理方式,相应的我们需要求出训练数据集的均值(mean_train)以及训练数据集的方差(std_train)。当我们归一化之后,我们将这样的数据集用于训练模型,最终我们需要使用我们训练出的这个模型来预测数据,对于这个测试数据集,我们需要使用同样的数据归一化的方式进行归一化处理,那么问题是对于测试数据集来说,我们应该怎样进行归一化处理呢?可能大多数人都会这样想,我们直接求出整个测试数据集的均值(mean_test)和方差(std_test),然后将其送入到模型中进行测试,不就ok了吗?这里面有一个陷阱,一定要注意,这样做是不对的。
在这里插入图片描述
  我们正确的做法应该是将我们的测试数据集使用训练数据集得到的 mean_train 和 std_train 相应的进行归一化。即 (x_test - mean_train) / std_train。为什么要这样做呢?

  主要有几个原因。首先最主要的原因在于测试数据是模拟真实的环境。我们从原始数据中划分出了一部分测试数据集,对于这个测试数据集,我们确实很容易得到它的均值和方差,但是不要忘了,我们训练出这个模型,是要让它在真实的环境中使用,可是在很多时候真实环境很有可能无法得到所有测试数据的均值和方差。举个简单的例子,比如说对于我们的鸢尾花识别来说,虽然我们可以得到测试数据中所有鸢尾花的相应的平均的特征,但是在实际使用的时候,我们只是每次来了一朵花,那么请问来的这一朵花的均值是多少?方差是多少呢?我们是无法获得这样的统计数据的。因此在实际上在真正的使用中,来了一朵新的鸢尾花,我们要将这朵新的鸢尾花的特征归一化,我们只能让它的特征减去训练数据集对应的 mean_train,再除以训练数据集所对应的方差。

  另外一点,将我们的数据进行归一化也是算法的一部分。换句话说,算法就包括把所有的数据减去 mean_train,再除以 std_train,针对后面来的所有的数据,我们也应该使用同样的方式来处理,然后来测试它的准确度,得到的才是这个算法真正的准确度。

  理解到了这一点,对于测试数据集的归一化处理。我们首先需要保存训练数据集得到的均值和方差。为了方便地进行这一步操作,sklearn 中对于数据的归一化专门封装了一个类 Scaler 。sklearn 的封装里面就是想办法将 Scaler 这个类与我们机器学习算法的整体使用流程是一致的。下图就表示了 Scaler 的流程。

在这里插入图片描述
  整个过程就是将我们的训练数据集 X_train,y_train 传入 Scaler 中,然后 Scaler 中也有一个 fit 方法,该 fit 算法就是求出这个训练数据集对应的一些统计指标,比如:均值,方差。之后 Scaler 中保存了关键信息,再来其它的样例之后,Scaler 就可以对于输入的样例进行 transform 得到相应的输出结果。对比机器学习算法流程,只是将 predict 改成了 transform。

下面我将用实际的代码来看一下 sklearn 对于数据的归一化这种封装方式。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上面测试可以发现,如果我们只将训练数据集归一化,没有将测试数据集归一化,得到的准确率只有0.33,所以我们在归一化的时候一定要注意,两个数据集都要进行归一化处理


封装 SatndardScaler

看完了 sklearn 中 Scaler 的使用,下面我们自己封装一个 StandardScaler。

# preprocessing.py

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"
        """而且fit必须在transform之前执行,所以mean_和scale_必须是非空的"""
        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 nunmber 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

测试:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


具体代码见 08 scikit-learn中的Scaler.ipynb + 08 测试封装的StandardScaler.ipynb

猜你喜欢

转载自blog.csdn.net/qq_41033011/article/details/108975425