组件图#

EvalML 组件图表示和描述了相关组件集合中的数据流。组件图由代表组件的节点以及代表每个组件的输入和输出应流向何处的节点对之间的边组成。它是 EvalML 管道提供的功能的主干,但它本身也是一个强大的数据结构。EvalML 目前支持线性组件图和 有向无环图 (DAG)

定义组件图#

可以通过指定描述图的组件和边的字典来定义组件图。

在此字典中,每个键都是组件的引用名称。每个对应的值都是一个列表,其中第一个元素是组件本身,其余元素是应连接到该组件的输入边。值中列出的组件可以是组件对象本身,也可以是其字符串名称。

这种结构与 Dask 计算图非常相似。

例如,在下面的代码示例中,我们有一个由两个组件组成的简单组件图:一个 Imputer 和一个 Random Forest Classifier。用于引用这两个组件的名称分别由键“My Imputer”和“RF Classifier”给出。字典中的每个值都是一个列表,其中第一个元素是对应于组件名称的组件,其余元素是输入,例如,“My Imputer”代表一个 Imputer 组件,其输入为“X”(原始特征矩阵)和“y”(原始目标)。

特征边指定为 "X""{component_name}.x"。例如,{"My Component": [MyComponent, "Imputer.x", ...]} 表示我们应该使用 Imputer 的特征输出作为 MyComponent 特征输入的一部分。类似地,目标边指定为 "y""{component_name}.y". {"My Component": [MyComponent, "Target Imputer.y", ...]} 表示我们应该使用 Target Imputer 的目标输出作为 MyComponent 的目标输入。

每个组件可以有多个特征输入,但只能有一个目标输入。所有输入边必须显式定义。

使用一个实际示例,我们定义一个由三个节点组成的简单组件图:一个 Imputer(“My Imputer”)、一个 One-Hot Encoder(“OHE”)和一个 Random Forest Classifier(“RF Classifier”)。

  • “My Imputer” 将原始 X 作为特征输入,将原始 y 作为目标输入

  • “OHE” 也将原始 X 作为特征输入,将原始 y 作为目标输入

  • “RF Classifer” 将来自“My Imputer”和“OHE”的连接特征输出作为特征输入,将原始 y 作为目标输入。

[1]:
from evalml.pipelines import ComponentGraph

component_dict = {
    "My Imputer": ["Imputer", "X", "y"],
    "OHE": ["One Hot Encoder", "X", "y"],
    "RF Classifier": [
        "Random Forest Classifier",
        "My Imputer.x",
        "OHE.x",
        "y",
    ],  # takes in multiple feature inputs
}
cg_simple = ComponentGraph(component_dict)

所有组件图必须以一个最终或终止节点结束。这可以是一个 transformer 或一个 estimator。下面,组件图是无效的,因为它有两个终止节点:“RF Classifier”和“EN Classifier”。

[2]:
# Can't instantiate a component graph with more than one terminus node (here: RF Classifier, EN Classifier)
component_dict = {
    "My Imputer": ["Imputer", "X", "y"],
    "RF Classifier": ["Random Forest Classifier", "My Imputer.x", "y"],
    "EN Classifier": ["Elastic Net Classifier", "My Imputer.x", "y"],
}

定义好组件图后,我们可以使用 .instantiate(parameters) 为每个组件指定参数值来实例化图。组件图中的所有组件在进行拟合、转换或预测之前都必须被实例化。

下面,我们实例化我们的图,并将 Imputer 的 numeric_impute_strategy 参数值设置为“most_frequent”。

[3]:
cg_simple.instantiate({"My Imputer": {"numeric_impute_strategy": "most_frequent"}})
[3]:
{'My Imputer': ['Imputer', 'X', 'y'], 'OHE': ['One Hot Encoder', 'X', 'y'], 'RF Classifier': ['Random Forest Classifier', 'My Imputer.x', 'OHE.x', 'y']}

组件图中的组件#

您可以使用 .get_component(name) 并提供唯一的组件名称来访问组件图中的任何组件。下面,我们可以获取 Imputer 组件并确认 numeric_impute_strategy 确实已被设置为“most_frequent”。

[4]:
cg_simple.get_component("My Imputer")
[4]:
Imputer(categorical_impute_strategy='most_frequent', numeric_impute_strategy='most_frequent', boolean_impute_strategy='most_frequent', categorical_fill_value=None, numeric_fill_value=None, boolean_fill_value=None)

您还可以使用 .get_inputs(name) 并提供唯一的组件名称来检索该组件的所有输入。

下面,我们可以获取“RF Classifier”组件,并确认我们使用 "My Imputer.x" 作为特征输入,使用 "y" 作为目标输入。

[5]:
cg_simple.get_inputs("RF Classifier")
[5]:
['My Imputer.x', 'OHE.x', 'y']

组件图计算顺序#

初始化时,每个组件图将生成一个拓扑顺序。我们可以通过调用 .compute_order 属性来访问此生成的顺序。此属性用于确定在调用 fittransform 期间应评估组件的顺序。

[6]:
cg_simple.compute_order
[6]:
['My Imputer', 'OHE', 'RF Classifier']

可视化组件图#

通过调用 .describe(),我们可以获得有关已实例化组件图的更多信息。此方法将美观地打印出图中的每个组件及其参数。

[7]:
# Using a more involved component graph with more complex edges
component_dict = {
    "Imputer": ["Imputer", "X", "y"],
    "Target Imputer": ["Target Imputer", "X", "y"],
    "OneHot_RandomForest": ["One Hot Encoder", "Imputer.x", "Target Imputer.y"],
    "OneHot_ElasticNet": ["One Hot Encoder", "Imputer.x", "y"],
    "Random Forest": ["Random Forest Classifier", "OneHot_RandomForest.x", "y"],
    "Elastic Net": [
        "Elastic Net Classifier",
        "OneHot_ElasticNet.x",
        "Target Imputer.y",
    ],
    "Logistic Regression": [
        "Logistic Regression Classifier",
        "Random Forest.x",
        "Elastic Net.x",
        "y",
    ],
}
cg_with_estimators = ComponentGraph(component_dict)
cg_with_estimators.instantiate({})
cg_with_estimators.describe()
1. Imputer
         * categorical_impute_strategy : most_frequent
         * numeric_impute_strategy : mean
         * boolean_impute_strategy : most_frequent
         * categorical_fill_value : None
         * numeric_fill_value : None
         * boolean_fill_value : None
2. Target Imputer
         * impute_strategy : most_frequent
         * fill_value : None
3. One Hot Encoder
         * top_n : 10
         * features_to_encode : None
         * categories : None
         * drop : if_binary
         * handle_unknown : ignore
         * handle_missing : error
4. One Hot Encoder
         * top_n : 10
         * features_to_encode : None
         * categories : None
         * drop : if_binary
         * handle_unknown : ignore
         * handle_missing : error
5. Random Forest Classifier
         * n_estimators : 100
         * max_depth : 6
         * n_jobs : -1
6. Elastic Net Classifier
         * penalty : elasticnet
         * C : 1.0
         * l1_ratio : 0.15
         * n_jobs : -1
         * multi_class : auto
         * solver : saga
7. Logistic Regression Classifier
         * penalty : l2
         * C : 1.0
         * n_jobs : -1
         * multi_class : auto
         * solver : lbfgs

我们还可以通过调用 .graph() 来可视化组件图。

[8]:
cg_with_estimators.graph()
[8]:
../_images/user_guide_component_graphs_18_0.svg

组件图方法#

与管道结构类似,我们可以调用 fittransformpredict

我们还可以调用 fit_features 来拟合除最后一个组件外的所有组件,以及调用 compute_final_component_features 来转换除最后一个组件外的所有组件。当您想了解哪些转换后的特征被传递到最后一个组件时,这两种方法可能很有用。

[9]:
from evalml.demos import load_breast_cancer

X, y = load_breast_cancer()
component_dict = {
    "My Imputer": ["Imputer", "X", "y"],
    "OHE": ["One Hot Encoder", "My Imputer.x", "y"],
}
cg_with_final_transformer = ComponentGraph(component_dict)
cg_with_final_transformer.instantiate({})
cg_with_final_transformer.fit(X, y)

# We can call `transform` for ComponentGraphs with a final transformer
cg_with_final_transformer.transform(X, y)
         Number of Features
Numeric                  30

Number of training examples: 569
Targets
benign       62.74%
malignant    37.26%
Name: count, dtype: object
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-evalml/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-evalml/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-evalml/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
[9]:
平均半径 平均纹理 平均周长 平均面积 平均平滑度 平均紧致度 平均凹度 平均凹点 平均对称性 平均分形维数 ... 最差半径 最差纹理 最差周长 最差面积 最差平滑度 最差紧致度 最差凹度 最差凹点 最差对称性 最差分形维数
0 17.99 10.38 122.80 1001.0 0.11840 0.27760 0.30010 0.14710 0.2419 0.07871 ... 25.380 17.33 184.60 2019.0 0.16220 0.66560 0.7119 0.2654 0.4601 0.11890
1 20.57 17.77 132.90 1326.0 0.08474 0.07864 0.08690 0.07017 0.1812 0.05667 ... 24.990 23.41 158.80 1956.0 0.12380 0.18660 0.2416 0.1860 0.2750 0.08902
2 19.69 21.25 130.00 1203.0 0.10960 0.15990 0.19740 0.12790 0.2069 0.05999 ... 23.570 25.53 152.50 1709.0 0.14440 0.42450 0.4504 0.2430 0.3613 0.08758
3 11.42 20.38 77.58 386.1 0.14250 0.28390 0.24140 0.10520 0.2597 0.09744 ... 14.910 26.50 98.87 567.7 0.20980 0.86630 0.6869 0.2575 0.6638 0.17300
4 20.29 14.34 135.10 1297.0 0.10030 0.13280 0.19800 0.10430 0.1809 0.05883 ... 22.540 16.67 152.20 1575.0 0.13740 0.20500 0.4000 0.1625 0.2364 0.07678
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
564 21.56 22.39 142.00 1479.0 0.11100 0.11590 0.24390 0.13890 0.1726 0.05623 ... 25.450 26.40 166.10 2027.0 0.14100 0.21130 0.4107 0.2216 0.2060 0.07115
565 20.13 28.25 131.20 1261.0 0.09780 0.10340 0.14400 0.09791 0.1752 0.05533 ... 23.690 38.25 155.00 1731.0 0.11660 0.19220 0.3215 0.1628 0.2572 0.06637
566 16.60 28.08 108.30 858.1 0.08455 0.10230 0.09251 0.05302 0.1590 0.05648 ... 18.980 34.12 126.70 1124.0 0.11390 0.30940 0.3403 0.1418 0.2218 0.07820
567 20.60 29.33 140.10 1265.0 0.11780 0.27700 0.35140 0.15200 0.2397 0.07016 ... 25.740 39.42 184.60 1821.0 0.16500 0.86810 0.9387 0.2650 0.4087 0.12400
568 7.76 24.54 47.92 181.0 0.05263 0.04362 0.00000 0.00000 0.1587 0.05884 ... 9.456 30.37 59.16 268.6 0.08996 0.06444 0.0000 0.0000 0.2871 0.07039

569 行 × 30 列

[10]:
cg_with_estimators.fit(X, y)

# We can call `predict` for ComponentGraphs with a final transformer
cg_with_estimators.predict(X)
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-evalml/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-evalml/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
[10]:
0      malignant
1      malignant
2      malignant
3      malignant
4      malignant
         ...
564    malignant
565    malignant
566    malignant
567    malignant
568       benign
Length: 569, dtype: category
Categories (2, object): ['benign', 'malignant']