ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

sklearn——转换器(Transformer)与预估器(estimator)

2021-10-29 09:34:13  阅读:265  来源: 互联网

标签:Transformer Xi fit unknown self transform estimator categories sklearn


sklearn——转换器(Transformer)与预估器(estimator)

文章目录

在我之前接触的sklearn中,有 SimpleImputerOrdinalEncoderOneHotEncoder,他们的共同点是都用于对数据特征预处理。

在对他们的使用中都无法避免遇到:fit_transformtransform。初时,还没有充分了解的我只是记住了这一特征,最后了解到 sklearnTransformerestimator的概念,认为有必要整合一下。

转换器 Transformer

由于在进行模型fit之前,需要先对数据集进行预处理,这里包括对空值的处理、对object变量的预处理。

可以看作需要对数据集进行一个转换,则这个时候就需要用上Transformer了,本质上SimpleImputerOrdinalEncoderOneHotEncoder 都属于 Transformer。

例如,原数据 X_train 经过一个SimpleImputer 后,得到了经过空值插补的新数据集 X_train_new

fit 与 fit_transform 与 transform

SimpleImputer 为例,若需要均值插补,那么在插补之前首先需要知道空值对应列的均值是多少。

fit 是先计算矩阵空值(缺失值)对应列的相关值大小,如均值、中位数、频率最高的数。

transform 则在根据fit 计算的值对输入的数据集进行变换。

故,在对一个新的数据集处理之前,需要先fit 一次,得到相关值,在transform 进行转换。但一般情况下,我们会直接使用 fit_transform

fit_transform 内部是先对数据集进行 fit,在顺势对其调用transform

>>>import numpy as np
>>>from sklearn.impute import SimpleImputer
>>>imp = SimpleImputer(missing_values=np.nan, strategy='mean')
>>>imp.fit([[1, 8], [np.nan, 4], [7, 6]])
SimpleImputer()
>>>X
array([[nan,  2.],
 [ 6., nan],
 [ 7., nan]])
>>>print(imp.transform(X))
[[4. 2.]
 [6. 6.]
 [7. 6.]]
>>> print(imp.fit_transform(X))
[[6.5 2. ]
 [6.  2. ]
 [7.  2. ]]

第10行是根据提前输入的数据进行fit, 再根据fit 保存的均值,来对X进行 transform。输入的数组第一列平均值为 (1 + 7)/2 = 4 ,第二列的均值是 (8 + 4 + 6)/3 = 6,即除数是非空值的个数。 得到均值后再直接插入X的空值部分,不考虑 X 的数据。

第14行,对 X 直接进行fit_transform 即对X 先 fit ,再对X 进行 transform ,道理同上。

值得注意的是

在对数据集中, 训练集和验证机进行转换的时候,只需要对训练集调用fit即可,对于验证机直接调用transform(),因为为数据集的一致性,对验证集的转换最好同训练集一致。 (例如对训练集进行OrdinalEncoder 编码, 若对验证机也调用 fit_transform,很有可能训练集验证集中,对于同一个 object值的编码不同,比如对训练集中的球的颜色红色编码为 3 ,验证集中却对其编码为 6)

扒拉了下源码(可以不看这部分,看上面结论就够了)

翻了下源码,SimpleImputerOrdinalEncoderOneHotEncoder都有基类class _BaseEncoder(TransformerMixin, BaseEstimator) ,虽然它也有基类TransformerMixin,但是这个代码我没看大明白, 只能看出return self.fit(X, **fit_params).transform(X), 先 fit 了一次,再直接调用了一次 transform

所以简单来说 fit_transform 即 先调用了一次 fit 再调用了一次 transform

class TransformerMixin:
    """Mixin class for all transformers in scikit-learn."""

    def fit_transform(self, X, y=None, **fit_params):
        """
        Fit to data, then transform it.
        拟合数据并转换它
        Fits transformer to `X` and `y` with optional parameters `fit_params`
        and returns a transformed version of `X`.
        Parameters
        ----------
        X : array-like of shape (n_samples, n_features)
            Input samples.
        y :  array-like of shape (n_samples,) or (n_samples, n_outputs), \
                default=None
            Target values (None for unsupervised transformations).
        **fit_params : dict
            Additional fit parameters.
        Returns
        -------
        X_new : ndarray array of shape (n_samples, n_features_new)
            Transformed array.
        """
        # non-optimized default implementation; override when a better
        # method is possible for a given clustering algorithm
        if y is None:
            # fit method of arity 1 (unsupervised transformation)
            return self.fit(X, **fit_params).transform(X)
        else:
            # fit method of arity 2 (supervised transformation)
            return self.fit(X, y, **fit_params).transform(X)

OneHotEncoder 为例,直接看它的,fit 和 transform, 会发现他们都调用了基类_BaseEncoder的 _fit() 和 transform()。

    def _fit(self, X, handle_unknown="error", force_all_finite=True):
        self._check_n_features(X, reset=True)
        self._check_feature_names(X, reset=True)
        X_list, n_samples, n_features = self._check_X(
            X, force_all_finite=force_all_finite
        )
        self.n_features_in_ = n_features

        if self.categories != "auto":
            if len(self.categories) != n_features:
                raise ValueError(
                    "Shape mismatch: if categories is an array,"
                    " it has to be of shape (n_features,)."
                )

        self.categories_ = []

        for i in range(n_features):
            Xi = X_list[i]
            if self.categories == "auto":
                cats = _unique(Xi)
            else:
                cats = np.array(self.categories[i], dtype=Xi.dtype)
                if Xi.dtype.kind not in "OUS":
                    sorted_cats = np.sort(cats)
                    error_msg = (
                        "Unsorted categories are not supported for numerical categories"
                    )
                    # if there are nans, nan should be the last element
                    stop_idx = -1 if np.isnan(sorted_cats[-1]) else None
                    if np.any(sorted_cats[:stop_idx] != cats[:stop_idx]) or (
                        np.isnan(sorted_cats[-1]) and not np.isnan(sorted_cats[-1])
                    ):
                        raise ValueError(error_msg)

                if handle_unknown == "error":
                    diff = _check_unknown(Xi, cats)
                    if diff:
                        msg = (
                            "Found unknown categories {0} in column {1}"
                            " during fit".format(diff, i)
                        )
                        raise ValueError(msg)
            self.categories_.append(cats)

    def _transform(
        self, X, handle_unknown="error", force_all_finite=True, warn_on_unknown=False
    ):
        self._check_feature_names(X, reset=False)
        self._check_n_features(X, reset=False)
        X_list, n_samples, n_features = self._check_X(
            X, force_all_finite=force_all_finite
        )

        X_int = np.zeros((n_samples, n_features), dtype=int)
        X_mask = np.ones((n_samples, n_features), dtype=bool)

        columns_with_unknown = []
        for i in range(n_features):
            Xi = X_list[i]
            diff, valid_mask = _check_unknown(Xi, self.categories_[i], return_mask=True)

            if not np.all(valid_mask):
                if handle_unknown == "error":
                    msg = (
                        "Found unknown categories {0} in column {1}"
                        " during transform".format(diff, i)
                    )
                    raise ValueError(msg)
                else:
                    if warn_on_unknown:
                        columns_with_unknown.append(i)
                    # Set the problematic rows to an acceptable value and
                    # continue `The rows are marked `X_mask` and will be
                    # removed later.
                    X_mask[:, i] = valid_mask
                    # cast Xi into the largest string type necessary
                    # to handle different lengths of numpy strings
                    if (
                        self.categories_[i].dtype.kind in ("U", "S")
                        and self.categories_[i].itemsize > Xi.itemsize
                    ):
                        Xi = Xi.astype(self.categories_[i].dtype)
                    elif self.categories_[i].dtype.kind == "O" and Xi.dtype.kind == "U":
                        # categories are objects and Xi are numpy strings.
                        # Cast Xi to an object dtype to prevent truncation
                        # when setting invalid values.
                        Xi = Xi.astype("O")
                    else:
                        Xi = Xi.copy()

                    Xi[~valid_mask] = self.categories_[i][0]
            # We use check_unknown=False, since _check_unknown was
            # already called above.
            X_int[:, i] = _encode(Xi, uniques=self.categories_[i], check_unknown=False)
        if columns_with_unknown:
            warnings.warn(
                "Found unknown categories in columns "
                f"{columns_with_unknown} during transform. These "
                "unknown categories will be encoded as all zeros",
                UserWarning,
            )

大致读了以下,说实话没有看太明白,但是很容易看出,_fit 和 _transform 在主要的循环部分都多次用到,self.categories_ 这个变量,而这个变量来自于sef._fit() 。 即transform 会直接使用 fit 中存储好的预设值。

预估器 Estimator

即 sklearn 中带有的各种算法模型。无论分类器或者回归都属于此类。

常见基础的如决策树、随机森林。

# 决策树
from sklearn.tree import DecisionTreeRegressor		// 用于回归问题
from sklearn.tree import DecisionTreeClassifier		// 用于分类问题
# 随机胜率
from sklearn.ensemble import RandomForestRegressor
# XGBoost
from xgboost import XGBRegressor

这些预估器在使用上大同小异,以决策树为例。

  • 先实例化一个 esitimator
  • 再对他进行 fit 拟合,注意这里的 fit 是 esitimator 自带的 fit。
  • 再调用 predict 进行预测、预估。
from sklearn.tree import DecisionTreeRegressor		// 用于回归问题
from sklearn.tree import DecisionTreeClassifier		// 用于分类问题

melbourne_model = DecisionTreeRegressor(random_state = 1)

#Fit model
melbourne_model.fit(X,y)

melbourne_model.predict(X.head())   // 进行模型预测

各模型的比较和详细解释不在这里赘述。

谨记,ML的基础永远是数学基础。

标签:Transformer,Xi,fit,unknown,self,transform,estimator,categories,sklearn
来源: https://blog.csdn.net/qq_40454401/article/details/121028050

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有