组件#

组件是 EvalML 中最低级别的构建块。每个组件代表一个应用于数据的基本操作。

所有组件都接受参数作为其 __init__ 方法的关键字参数。这些参数可用于配置行为。

每个组件类定义都必须包含一个人类可读的组件 name。此外,每个组件类可以通过定义一个包含相关参数的 hyperparameter_ranges 属性来暴露用于 AutoML 搜索的参数。

EvalML 将组件分为两类:转换器 (transformers)估计器 (estimators)

转换器 (Transformers)#

转换器继承自 Transformer 类,并定义了一个 fit 方法来从训练数据中学习信息,以及一个 transform 方法将学习到的转换应用于新数据。

例如,一个 填充器 (imputer) 配置了所需的填充策略,例如均值。填充器的 fit 方法会从训练数据中学习均值,而 transform 方法会将学习到的均值填充到新数据中的任何缺失值处。

所有转换器都可以单独执行 fittransform,或者通过调用 fit_transform 在一步中完成。在某些情况下,定义自定义的 fit_transform 方法可以实现有用的性能优化。

[1]:
import numpy as np
import pandas as pd
from evalml.pipelines.components import SimpleImputer

X = pd.DataFrame([[1, 2, 3], [1, np.nan, 3]])
display(X)
0 1 2
0 1 2.0 3
1 1 NaN 3
[2]:
import woodwork as ww

imp = SimpleImputer(impute_strategy="mean")

X.ww.init()
X = imp.fit_transform(X)
display(X)
0 1 2
0 1 2.0 3
1 1 2.0 3

下面是 EvalML 中包含的所有转换器的列表

[3]:
from evalml.pipelines.components.utils import all_components, Estimator, Transformer

for component in all_components():
    if issubclass(component, Transformer):
        print(f"Transformer: {component.name}")
Transformer: Time Series Regularizer
Transformer: Drop NaN Rows Transformer
Transformer: Replace Nullable Types Transformer
Transformer: Drop Rows Transformer
Transformer: URL Featurizer
Transformer: Email Featurizer
Transformer: Log Transformer
Transformer: STL Decomposer
Transformer: Polynomial Decomposer
Transformer: DFS Transformer
Transformer: Time Series Featurizer
Transformer: Natural Language Featurizer
Transformer: LSA Transformer
Transformer: Drop Null Columns Transformer
Transformer: DateTime Featurizer
Transformer: PCA Transformer
Transformer: Linear Discriminant Analysis Transformer
Transformer: Select Columns By Type Transformer
Transformer: Select Columns Transformer
Transformer: Drop Columns Transformer
Transformer: Oversampler
Transformer: Undersampler
Transformer: Standard Scaler
Transformer: Time Series Imputer
Transformer: Target Imputer
Transformer: Imputer
Transformer: KNN Imputer
Transformer: Per Column Imputer
Transformer: Simple Imputer
Transformer: RFE Selector with RF Regressor
Transformer: RFE Selector with RF Classifier
Transformer: RF Regressor Select From Model
Transformer: RF Classifier Select From Model
Transformer: Ordinal Encoder
Transformer: Label Encoder
Transformer: Target Encoder
Transformer: One Hot Encoder

估计器 (Estimators)#

每个估计器封装了一个机器学习算法。估计器继承自 Estimator 类,并定义了一个 fit 方法来从训练数据中学习信息,以及一个 predict 方法用于从新数据生成预测。分类估计器还应该定义一个 predict_proba 方法用于生成预测概率。

每个估计器类都定义了一个 model_family 属性,指示使用了哪种类型的模型。

这里是一个使用 LogisticRegressionClassifier 估计器在简单数据集上进行拟合和预测的示例

[4]:
from evalml.pipelines.components import LogisticRegressionClassifier

clf = LogisticRegressionClassifier()

X = X
y = [1, 0]

clf.fit(X, y)
clf.predict(X)
[4]:
0    0
1    0
dtype: int64

下面是 EvalML 中包含的所有估计器的列表

[5]:
from evalml.pipelines.components.utils import all_components, Estimator, Transformer

for component in all_components():
    if issubclass(component, Estimator):
        print(f"Estimator: {component.name}")
Estimator: Stacked Ensemble Regressor
Estimator: Stacked Ensemble Classifier
Estimator: VARMAX Regressor
Estimator: ARIMA Regressor
Estimator: Exponential Smoothing Regressor
Estimator: SVM Regressor
Estimator: Prophet Regressor
Estimator: Multiseries Time Series Baseline Regressor
Estimator: Time Series Baseline Estimator
Estimator: Decision Tree Regressor
Estimator: Baseline Regressor
Estimator: Extra Trees Regressor
Estimator: XGBoost Regressor
Estimator: CatBoost Regressor
Estimator: Random Forest Regressor
Estimator: LightGBM Regressor
Estimator: Linear Regressor
Estimator: Elastic Net Regressor
Estimator: SVM Classifier
Estimator: KNN Classifier
Estimator: Decision Tree Classifier
Estimator: LightGBM Classifier
Estimator: Baseline Classifier
Estimator: Extra Trees Classifier
Estimator: Elastic Net Classifier
Estimator: CatBoost Classifier
Estimator: XGBoost Classifier
Estimator: Random Forest Classifier
Estimator: Logistic Regression Classifier

定义自定义组件#

通过遵循以下步骤,EvalML 允许您轻松创建自己的自定义组件。

自定义转换器#

您的转换器必须继承自正确的子类。在本例中,对于转换数据的组件,应继承自 Transformer。接下来我们将使用 EvalML 的 DropNullColumns 作为示例。

[6]:
from evalml.pipelines.components import Transformer
from evalml.utils import (
    infer_feature_types,
)


class DropNullColumns(Transformer):
    """Transformer to drop features whose percentage of NaN values exceeds a specified threshold"""

    name = "Drop Null Columns Transformer"
    hyperparameter_ranges = {}

    def __init__(self, pct_null_threshold=1.0, random_seed=0, **kwargs):
        """Initalizes an transformer to drop features whose percentage of NaN values exceeds a specified threshold.

        Args:
            pct_null_threshold(float): The percentage of NaN values in an input feature to drop.
                Must be a value between [0, 1] inclusive. If equal to 0.0, will drop columns with any null values.
                If equal to 1.0, will drop columns with all null values. Defaults to 0.95.
        """
        if pct_null_threshold < 0 or pct_null_threshold > 1:
            raise ValueError(
                "pct_null_threshold must be a float between 0 and 1, inclusive."
            )
        parameters = {"pct_null_threshold": pct_null_threshold}
        parameters.update(kwargs)

        self._cols_to_drop = None
        super().__init__(
            parameters=parameters, component_obj=None, random_seed=random_seed
        )

    def fit(self, X, y=None):
        """Fits DropNullColumns component to data

        Args:
            X (pd.DataFrame): The input training data of shape [n_samples, n_features]
            y (pd.Series, optional): The target training data of length [n_samples]

        Returns:
            self
        """
        pct_null_threshold = self.parameters["pct_null_threshold"]
        X_t = infer_feature_types(X)
        percent_null = X_t.isnull().mean()
        if pct_null_threshold == 0.0:
            null_cols = percent_null[percent_null > 0]
        else:
            null_cols = percent_null[percent_null >= pct_null_threshold]
        self._cols_to_drop = list(null_cols.index)
        return self

    def transform(self, X, y=None):
        """Transforms data X by dropping columns that exceed the threshold of null values.

        Args:
            X (pd.DataFrame): Data to transform
            y (pd.Series, optional): Ignored.

        Returns:
            pd.DataFrame: Transformed X
        """
        X_t = infer_feature_types(X)
        return X_t.drop(self._cols_to_drop)

必需字段#

  • name: 人类可读的名称。

  • modifies_features: 一个布尔值,指定此组件在 transform 期间是否修改(子集化或转换)特征变量。

  • modifies_target: 一个布尔值,指定此组件在 transform 期间是否修改(子集化或转换)目标变量。

必需方法#

同样,由于 Transformer 是一个抽象基类,您需要重写一些方法

  • __init__(): 您的转换器的 __init__() 方法需要调用 super().__init__() 并传入三个参数:一个包含组件参数的 parameters 字典、component_objrandom_seed 值。您可以看到上面 component_obj 设置为 None,我们稍后将深入讨论 component_obj

  • fit(): fit() 方法负责在训练数据上拟合您的组件。它应该返回组件对象。

  • transform(): 拟合组件后,transform() 方法将接收新数据并进行相应的转换。它应该返回一个初始化了 woodwork 的 pandas 数据框。注意:组件必须先调用 fit(),然后才能调用 transform()

您也可以调用或重写将 fit()transform() 合并到一个方法中的 fit_transform()

自定义估计器#

您的估计器必须继承自正确的子类。在本例中,对于预测新目标值的组件,应继承自 Estimator。接下来我们将使用 EvalML 的 BaselineRegressor 作为示例。

[7]:
import numpy as np
import pandas as pd

from evalml.model_family import ModelFamily
from evalml.pipelines.components.estimators import Estimator
from evalml.problem_types import ProblemTypes


class BaselineRegressor(Estimator):
    """Regressor that predicts using the specified strategy.

    This is useful as a simple baseline regressor to compare with other regressors.
    """

    name = "Baseline Regressor"
    hyperparameter_ranges = {}
    model_family = ModelFamily.BASELINE
    supported_problem_types = [
        ProblemTypes.REGRESSION,
        ProblemTypes.TIME_SERIES_REGRESSION,
    ]

    def __init__(self, strategy="mean", random_seed=0, **kwargs):
        """Baseline regressor that uses a simple strategy to make predictions.

        Args:
            strategy (str): Method used to predict. Valid options are "mean", "median". Defaults to "mean".
            random_seed (int): Seed for the random number generator. Defaults to 0.

        """
        if strategy not in ["mean", "median"]:
            raise ValueError(
                "'strategy' parameter must equal either 'mean' or 'median'"
            )
        parameters = {"strategy": strategy}
        parameters.update(kwargs)

        self._prediction_value = None
        self._num_features = None
        super().__init__(
            parameters=parameters, component_obj=None, random_seed=random_seed
        )

    def fit(self, X, y=None):
        if y is None:
            raise ValueError("Cannot fit Baseline regressor if y is None")
        X = infer_feature_types(X)
        y = infer_feature_types(y)

        if self.parameters["strategy"] == "mean":
            self._prediction_value = y.mean()
        elif self.parameters["strategy"] == "median":
            self._prediction_value = y.median()
        self._num_features = X.shape[1]
        return self

    def predict(self, X):
        X = infer_feature_types(X)
        predictions = pd.Series([self._prediction_value] * len(X))
        return infer_feature_types(predictions)

    @property
    def feature_importance(self):
        """Returns importance associated with each feature. Since baseline regressors do not use input features to calculate predictions, returns an array of zeroes.

        Returns:
            np.ndarray (float): An array of zeroes

        """
        return np.zeros(self._num_features)

必需字段#

  • name: 人类可读的名称。

  • model_family - 此组件所属的 EvalML 模型族 (model_family)

  • supported_problem_types - 此组件支持的 EvalML 问题类型 (problem_types) 列表

  • modifies_features: 一个布尔值,指定是否应将 predictpredict_proba 的返回值用作特征。

  • modifies_target: 一个布尔值,指定是否应将 predictpredict_proba 的返回值用作目标变量。

模型族和问题类型包括

[8]:
from evalml.model_family import ModelFamily
from evalml.problem_types import ProblemTypes

print("Model Families:\n", [m.value for m in ModelFamily])
print("Problem Types:\n", [p.value for p in ProblemTypes])
Model Families:
 ['k_neighbors', 'random_forest', 'svm', 'xgboost', 'lightgbm', 'linear_model', 'catboost', 'extra_trees', 'ensemble', 'decision_tree', 'exponential_smoothing', 'arima', 'varmax', 'baseline', 'prophet', 'vowpal_wabbit', 'none']
Problem Types:
 ['binary', 'multiclass', 'regression', 'time series regression', 'time series binary', 'time series multiclass', 'multiseries time series regression']

必需方法#

  • __init__() - 您的估计器的 __init__() 方法需要调用 super().__init__() 并传入三个参数:一个包含组件参数的 parameters 字典、component_objrandom_seed 值。

  • fit() - fit() 方法负责在训练数据上拟合您的组件。

  • predict() - 拟合组件后,predict() 方法将接收新数据并预测新的目标值。注意:组件必须先调用 fit(),然后才能调用 predict()

  • feature_importance - feature_importance 是一个 Python property,它返回与每个特征相关的特征重要性列表。

如果您的估计器处理分类问题,它还需要一个额外的方法

  • predict_proba() - 此方法预测分类标签的概率估计值

封装第三方对象的组件#

component_obj 参数用于封装第三方对象并在组件实现中使用它们。如果您使用 component_obj,您需要定义 __init__() 并传入也实现了上述必需方法的相关对象。但是,如果 component_obj 不遵循 EvalML 组件约定,您可能需要根据需要重写方法。下面是 EvalML 的 LinearRegressor 示例。

[9]:
from sklearn.linear_model import LinearRegression as SKLinearRegression

from evalml.model_family import ModelFamily
from evalml.pipelines.components.estimators import Estimator
from evalml.problem_types import ProblemTypes


class LinearRegressor(Estimator):
    """Linear Regressor."""

    name = "Linear Regressor"
    model_family = ModelFamily.LINEAR_MODEL
    supported_problem_types = [ProblemTypes.REGRESSION]

    def __init__(
        self, fit_intercept=True, normalize=False, n_jobs=-1, random_seed=0, **kwargs
    ):
        parameters = {
            "fit_intercept": fit_intercept,
            "normalize": normalize,
            "n_jobs": n_jobs,
        }
        parameters.update(kwargs)
        linear_regressor = SKLinearRegression(**parameters)
        super().__init__(
            parameters=parameters,
            component_obj=linear_regressor,
            random_seed=random_seed,
        )

    @property
    def feature_importance(self):
        return self._component_obj.coef_

AutoML 的超参数范围#

hyperparameter_ranges 是一个字典,将参数名 (str) 映射到该参数的允许范围 (SkOpt Space)。对于类别空间,接受列表和 skopt.space.Categorical 值。

AutoML 将在每个参数的允许范围内执行搜索,以选择在这些范围内产生最佳性能的模型。AutoML 从组件的 hyperparameter_ranges 类属性中获取每个组件的允许范围。您在 hyperparameter_ranges 中为其添加条目的任何组件参数都将包含在 AutoML 搜索中。如果省略参数,AutoML 将在所有流水线中使用默认值。

生成组件代码#

在 EvalML 中定义组件后,您可以生成字符串 Python 代码来重新创建此组件,然后可以将其保存并在其他地方使用 EvalML 运行。generate_component_code 需要一个组件实例作为输入。此方法也适用于自定义组件,但它不会返回定义自定义组件所需的代码。

[10]:
from evalml.pipelines.components import LogisticRegressionClassifier
from evalml.pipelines.components.utils import generate_component_code

lr = LogisticRegressionClassifier(C=5)
code = generate_component_code(lr)
print(code)
from evalml.pipelines.components.estimators.classifiers.logistic_regression_classifier import LogisticRegressionClassifier

logisticRegressionClassifier = LogisticRegressionClassifier(**{'penalty': 'l2', 'C': 5, 'n_jobs': -1, 'multi_class': 'auto', 'solver': 'lbfgs'})
[11]:
# this string can then be copy and pasted into a separate window and executed as python code
exec(code)
[12]:
# We can also do this for custom components
from evalml.pipelines.components.utils import generate_component_code

myDropNull = DropNullColumns()
print(generate_component_code(myDropNull))
dropNullColumnsTransformer = DropNullColumns(**{'pct_null_threshold': 1.0})

自定义分类组件的期望#

EvalML 对自定义分类组件的实现有以下期望

  • 分类目标范围为 0 到 n-1,并且是整数。

  • 对于分类估计器,predict_proba 的列顺序必须与目标的顺序匹配,并且列名必须是 0 到 n-1 的整数。