刚接触自动化机器学习的时候,我对TPOT是有点将信将疑的。毕竟手动调参、特征工程、模型选型这一套活,做了这么多年,你说一个库靠“进化”就能把整条流水线给我搭好,换成谁都得先打个问号。但真正跑过几次之后,我的看法变了:TPOT不是玩具,它是一套正经的流水线搜索框架,核心思路甚至比很多AutoML平台更符合直觉——它不只会调超参,它会连预处理、特征选择、特征构造、模型选择、超参组合一起帮你搜出来。
这篇文章就围绕TPOT这一个库来讲,会涉及它底层的进化算法机制、完整的上手路径、几个真正影响搜索效率的参数、如何用config_dict和Template限制搜索空间,以及我在真实数据集上踩过的坑。适合刚接触AutoML的读者,也适合已经跑通样例但觉得效果不理想、想进一步控制搜索过程的同学。
1. AutoML解决的痛点:流水线搭建为什么比模型调参更耗时
1.1 手动搭建流水线的隐性成本
很多人对机器学习工作流的理解是“选一个模型、调调参、看准确率”。但真正在业务里做过一次完整建模的人都知道,大头工作根本不在这里。数据清洗之后,你要决定要不要做标准化、要不要做PCA降维、特征里有没有类别型变量需要编码、是选KBest还是用树模型自带的特征重要性做筛选、模型用线性类还是集成类……这些步骤之间还有先后顺序,顺序不同结果可能差一大截。
这个组合空间有多大?拿sklearn里常见的预处理器和模型估算一下:预处理方法十几种,特征选择方法七八种,模型也有十几种,再加上每个模型自己的超参空间。排列组合下来,轻易就是几万到几十万种可能。手动一个个试,时间成本根本承受不起。更重要的是,很多组合方式是人脑容易忽略的,比如“标准化之后接多项式特征扩展,再进逻辑回归”这类操作,看起来反直觉,但某些数据上效果就是比默认流程好。
TPOT解决的就是这件事。它把“流水线长什么样”这个问题本身变成了一个搜索问题,用进化算法在一个巨大的流水线空间里找出评分最优的组合。它的输出不是一堆实验记录,而是一段可以直接导出的Python代码,这条流水线包含完整的预处理、特征处理、模型结构,甚至带好了超参数值。
1.2 TPOT在AutoML生态里的定位
市面上AutoML工具不少,Auto-sklearn用的是贝叶斯优化加元学习,H2O AutoML靠的是多个基模型堆叠加网格搜索,FLAML侧重低成本搜索。TPOT走的是另一条路——遗传编程。它把流水线当成一个程序树,通过类似于生物进化的选择、交叉、变异过程,迭代出越来越好的流水线个体。
这些工具没有绝对的好坏,只有适合的场景。TPOT的优势在于两点:第一,搜索空间足够宽,不局限于某个模型族,连特征工程算子都能参与搜索;第二,结果可解释、可落地,导出的代码是纯sklearn风格的,你可以拿去做二次改造,也可以直接嵌入到生产环境里,不像某些AutoML平台输出一个黑盒模型,部署时还要依赖平台本身。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. TPOT的进化算法内核:流水线是怎样被“进化”出来的
2.1 流水线如何被表示成一棵树
理解TPOT的运作方式,先要理解它的数据结构。TPOT里的每一条候选流水线都会被表示成一棵程序树,树的内部节点是数据转换操作,根节点是模型估算器,叶子节点是输入特征。
举个例子,“标准化 → PCA降维 → 随机森林”这条流水线,在TPOT内部的树结构大概是:根节点是RandomForestClassifier,它的左子节点是PCA,PCA下面再接StandardScaler,特征数据从叶子节点流入,经过层层变换后到达根节点完成分类。
这种树状表示法来自遗传编程的传统。和直接用字符串记录流水线步骤相比,树结构最大的好处是方便做后续的交叉和变异操作——TPOT可以随机交换两棵树的某个子树,也可以替换某个节点上的算子,而这些操作不会破坏整条流水线的执行逻辑。
TPOT在生成初始种群时,会随机创建一批这样的树,树的深度、节点组合都有一定限制,避免初始个体就复杂到跑不动。这一步相当于“先想出一堆乱七八糟的尝试方案”。
2.2 选择、交叉、变异:三个核心算子怎么工作
进化算法迭代的过程,和自然界生物进化的逻辑一致:
- 评估:种群中的每个个体都在训练集上做交叉验证,得到一个评分(比如accuracy、F1、AUC)。评分越高意味着这个流水线个体在当前数据上表现越好。
- 选择:TPOT用锦标赛选择机制,从种群中随机抽出一部分个体,挑出评分最高的进入下一代。这个策略避免了单纯按分数排序导致种群过早收敛。
- 交叉:两条评分不错的流水线会被选中配对,交换各自的一部分子树,生成新的流水线后代。这个操作让有价值的局部结构在个体间传播。
- 变异:随机修改个体中的节点,比如把逻辑回归换成SVM,或者把某个超参数从100改成200,也可以增加一层特征处理节点。
每一轮这样的迭代就是一代(generation)。经过足够多代的进化,种群中会留下大量在交叉验证上表现优秀的流水线个体。最后TPOT会从历史评估过的所有个体中选一个最优的,导出为最终代码。
2.3 Pareto前沿:不止看准确率,还看复杂度
这里有一个很关键的设计:TPOT在最终决策时,不是单纯按照指标分数选最高者。它会维护一个Pareto前沿——在“交叉验证得分”和“流水线复杂度”两个维度上寻找平衡点。
流水线复杂度的计算方式和树的节点数、算子本身的复杂度有关。为什么要管复杂度?因为越复杂的流水线越容易过拟合训练集,且在实际预测时的稳定性、可解释性都会变差。一条准确率只低了0.1个百分点但结构简单得多的流水线,通常更值得使用。
在TPOT里可以通过early_stop参数结合Pareto前沿来决定是否提前终止搜索,这一点后面会细说。理解Pareto前沿的意义在于:TPOT追求的是“性价比最优”的流水线,不是“训练集上分数最高”的流水线。
3. 第一次运行TPOT:从安装到导出可部署的Python代码
3.1 环境准备与安装
TPOT是一个Python库,基于scikit-learn开发,依赖numpy、pandas、scipy这些常规科学计算包。推荐用Python 3.8以上版本,虚拟环境按需创建,别直接装进base环境,这是所有Python项目都该有的基本习惯。
安装方式很简单:
bash复制pip install tpot
如果你在用Anaconda,也可以用:
bash复制conda install -c conda-forge tpot
安装完成后可以验证一下版本:
python复制import tpot
print(tpot.__version__)
对于小数据集和入门学习,默认安装就够用。如果要在大数据集上分布式跑,还需要额外装dask和distributed,这部分在后面的加速方案章节展开。
3.2 最小可运行示例:iris数据集
为了快速建立直观感受,先跑一个最小示例。用sklearn自带的iris数据集,流程很简单:加载数据、划分训练测试集、创建TPOTClassifier、fit、导出。
python复制from tpot import TPOTClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
tpot = TPOTClassifier(
generations=5,
population_size=20,
cv=5,
scoring='accuracy',
verbosity=2,
random_state=42,
n_jobs=-1,
)
tpot.fit(X_train, y_train)
print("Test accuracy:", tpot.score(X_test, y_test))
tpot.export('best_pipeline.py')
这段代码里generations=5表示进化5代,population_size=20表示每一代有20个候选流水线。也就是说,整个搜索过程会评估大约100条流水线(还要算上交叉、变异产生的子代),每条流水线做5折交叉验证。对iris这种小数据集,几十秒就能跑完。
跑完之后,当前目录下会生成一个best_pipeline.py文件。打开它,你会看到一段完整的、可以直接运行的sklearn代码,类似下面这样:
python复制import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import train_test_split
# Average CV score on the training set was: 0.977...
exported_pipeline = GradientBoostingClassifier(
learning_rate=0.1,
max_depth=3,
max_features=0.8,
min_samples_leaf=8,
min_samples_split=10,
n_estimators=100,
subsample=0.9
)
if __name__ == '__main__':
...
这就是TPOT的核心交付物:一段不依赖TPOT本身、只依赖sklearn家族库的预测代码。你完全可以把这段代码拿去对接生产环境,或者在此基础上继续微调。
3.3 解读导出的流水线:看结构而不是只看分数
导出代码里往往还有一段注释,写着训练集上交叉验证的平均分。很多人拿到这段代码,简单验证一下测试集分数就完事了。我的建议是:先看结构,再看分数。
看结构的意思是,你要搞清楚TPOT帮你选了哪些算子、算子之间的顺序是什么、为什么这样的组合会有效。比如它导出了StandardScaler -> SelectKBest -> RandomForestClassifier,说明在这个数据集上,特征缩放和特征选择对随机森林是有正向作用的。这个信息本身就有业务价值——你可以把它作为后续手工建模的起点。
另外,tpot.fitted_pipeline_属性保存的是最终选中的sklearn Pipeline对象,可以直接用来做预测:
python复制pipeline = tpot.fitted_pipeline_
predictions = pipeline.predict(X_test)
如果要概率输出,比如二分类场景要算AUC,记得用predict_proba,导出的代码里有些分类器是支持这个方法的,直接调用即可。
4. 决定搜索效率的关键参数:generations、population_size、scoring和max_time_mins
4.1 种群规模和进化代数怎么配
generations和population_size是TPOT里最重要的两个参数,它们直接决定了搜索的广度和深度。可以这么理解:population_size是每一代同时尝试多少个流水线方案,generations是总共进化多少轮。
两者相乘大体上决定了TPOT要评估的流水线总数。但实际的评估次数还会更多,因为交叉和变异产生的新个体也都要参与评估。
参数配比有一些经验可以参考:
- 小数据集、快速基线:
generations=5, population_size=20,总共100条左右的流水线,几分钟内跑完,用来快速确认AutoML在这个数据上有没有价值。 - 中等规模、认真搜索:
generations=50, population_size=50,搜索规模2500条流水线,运行时间从几十分钟到几小时不等,适合离线场景。 - 大体量、追求最优:
generations=100, population_size=100,搜索规模上万条,建议配合max_time_mins做时间上限控制。
一个常见误区是只加大population_size而不加generations。种群大但进化轮数少,相当于一次撒了一大堆随机尝试,但缺乏迭代优化;反过来,种群小但代数多,每一代的选择压力就会过大,容易早熟收敛到局部最优。所以在增加某一个参数时,另一个也要同步考虑。
4.2 scoring选择:不同任务类型要选对度量
TPOT支持多种评估指标,默认情况下分类用'accuracy',回归用'neg_mean_squared_error'。但你如果处理的是不平衡数据集,准确率是一个非常糟糕的评估指标——样本里90%是负类,模型全预测负类也有90%准确率,但这种模型在业务上毫无价值。
常见替代方案:
- 二分类不平衡:用
'roc_auc'或者'f1' - 多分类不平衡:用
'f1_macro'或者'f1_weighted' - 回归任务:用
'neg_mean_absolute_error'或'r2'
python复制tpot = TPOTClassifier(
scoring='roc_auc',
# ...
)
TPOT在内部用交叉验证评估每条流水线的scoring指标,所以scoring的选择会直接影响进化方向。你选accuracy,它就往提高准确率的方向进化;你选roc_auc,它就往提升排序能力的方向进化。这决定了最终得到的流水线是“服务于什么目标”的。
4.3 max_time_mins:给搜索上个闹钟
TPOT的搜索很容易失控。你设了generations=100, population_size=100,每条流水线5折交叉验证,如果数据量再大一点,一次运行跑一整天都不奇怪。所以实际使用中,max_time_mins是必设参数。
python复制tpot = TPOTClassifier(
generations=100,
population_size=100,
max_time_mins=60,
# ...
)
设置max_time_mins=60之后,TPOT会在运行时间达到60分钟时停止搜索,并返回当前Pareto前沿上的最优个体。这种方式特别适合有交付时限的场景。需要注意,max_time_mins和generations之间是“谁先到就听谁”的关系——进化代数提前跑完就正常结束,时间上限先到就提前终止。
还有一个容易被忽视的细节:max_time_mins设得太小时,TPOT可能连完整进化一代都跑不完,此时它会直接使用已经评估过的个体里最好的一个返回。这种情况下建议适度增大时间限制,或者缩小population_size,让进化过程至少能正常迭代几代。
5. 用config_dict和Template给TPOT戴上“紧箍咒”
5.1 为什么默认配置可能不适合你的数据
TPOT默认的搜索空间很宽,几乎涵盖了sklearn里所有常用预处理器、特征选择器和分类器,部分版本还包括xgboost、lightgbm这类外部库。理论上空间越宽越有可能找到更好的流水线,但在实际中,过宽的搜索空间会带来两个问题:
第一,运行时间暴涨。搜索空间大意味着评估一个个体时可能触碰到更耗时的算子组合,比如某些核函数的SVM在大样本上非常慢。
第二,搜索效率下降。如果数据集只有几千个样本,有些复杂的集成模型或者特定的特征算子组合根本没什么意义,白白占用进化算子的评估名额。
我处理过的几个真实项目里,默认配置通常会在前几代搜出大量包含朴素贝叶斯、逻辑回归这类简单模型的个体,但对某些特征高度非线性的数据,这些模型注定到不了高分区间,等于浪费了搜索资源。
5.2 自定义config_dict:把搜索空间限定在合理范围
TPOT提供了config_dict参数,允许你自定义搜索空间。你可以在默认配置的基础上增删算子,也可以完全从零写一个配置。
比如你明确知道这个数据用树模型效果会好,那就把搜索空间限定到决策树类集成模型加少量预处理算子:
python复制from tpot import TPOTClassifier
my_config = {
'sklearn.ensemble.RandomForestClassifier': {
'n_estimators': [100, 200, 300],
'max_features': ['auto', 'sqrt'],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
},
'sklearn.ensemble.ExtraTreesClassifier': {
'n_estimators': [100, 200],
'max_features': ['auto', 'sqrt'],
'min_samples_split': [2, 5],
},
'sklearn.ensemble.GradientBoostingClassifier': {
'learning_rate': [0.01, 0.05, 0.1],
'n_estimators': [100, 200],
'max_depth': [3, 5],
},
'sklearn.preprocessing.StandardScaler': {},
'sklearn.preprocessing.RobustScaler': {},
'sklearn.decomposition.PCA': {
'n_components': [0.85, 0.9, 0.95],
'svd_solver': ['full'],
},
}
tpot = TPOTClassifier(
generations=30,
population_size=40,
config_dict=my_config,
verbosity=2,
random_state=42,
)
这里有个细节值得注意:配置字典的value也是一个字典,key是超参数名,value是超参数候选值列表。TPOT在进化过程中会从这些候选值里随机选择,再通过变异算子尝试不同的取值组合。如果你的某个算子不需要任何超参搜索,value可以传空字典{},TPOT只会尝试该算子本身。
如果想在默认配置基础上做增减,TPOT也提供了配置合并的方式。你可以先获取默认配置字典,然后修改它:
python复制from tpot.config import classifier_config_dict
my_config = classifier_config_dict.copy()
# 移除某些算子
my_config.pop('sklearn.svm.SVC', None)
my_config.pop('sklearn.linear_model.LogisticRegression', None)
# 添加自定义算子
my_config['sklearn.ensemble.HistGradientBoostingClassifier'] = {
'learning_rate': [0.01, 0.1],
'max_iter': [100, 200],
}
tpot = TPOTClassifier(config_dict=my_config)
5.3 Template:限制流水线的固定结构
config_dict控制的是算子范围,Template控制的是流水线的结构形式。如果你的业务对流水线的结构有硬性要求,比如“先降维,再进分类器”,那可以用Template指定这个固定的模式。
python复制tpot = TPOTClassifier(
template='PCA-Classifier',
config_dict=my_config,
)
Template的写法用连字符连接算子类别:StandardScaler-PCA-Classifier表示先标准化再PCA降维最后分类;“Classifier”是一个通配符,表示任意分类器。使用Template之后,TPOT不会再尝试其他结构的流水线,只会在你给定的框架内搜索算子和超参。
这个功能特别适合流水线结构有业务约束的场景,比如有些数据必须在进入模型前做特定形式的去相关处理,或者某些特征必须经过固定的编码流程。灵活性和“不失控”往往是矛盾的,Template把这个问题用最简单的方式解决了。
6. 真实数据场景下的六个坑:缺失值、不平衡、数据泄露和运行时长
6.1 缺失值处理:TPOT的Imputer不是银弹
TPOT内部有一个默认的Imputer策略,会在数据进入流水线之前填充缺失值。但它的默认策略比较简单:用列均值或中位数填充。如果你把含大量缺失值的原始数据直接丢给TPOT,可能会吃到这样的毒打:某些特征缺失率超过50%,均值填充等于把半个特征变成常量,模型学不到任何有效信息。
我的建议是在进入TPOT之前,先把缺失值处理逻辑确定下来。可以先用SimpleImputer或KNNImputer做一次填充,把填充后完整的数据交给TPOT;也可以在config_dict里添加带自定义策略的Imputer算子,让TPOT自己去搜索用哪种填充策略组合更好。
这里要特别提醒数据泄露的问题:填充统计量必须在训练集上计算,再应用到测试集。如果你在划分数据集之前就对全量数据做了填充,那么测试集的信息已经泄露到训练过程里了,最终评估的分数会偏乐观。TPOT内部做交叉验证时会为每一折单独拟合适配器,这一点没问题;但你在外部预处理时一定要自己做对train-test split和fit-transform的次序。
6.2 类别不平衡:TPOT会“假装看不见”
TPOT不会自动处理类别不平衡,默认情况下它用分层交叉验证来保证每折的类别比例一致,但这只能保证训练集和验证集的分布一致,并不能让模型学会少数类的模式。
要在TPOT中处理不平衡,有几个思路:
- 换scoring指标:从
accuracy换成roc_auc或f1,让进化方向偏向少数类的表现。 - 在流水线里加采样器:通过config_dict启用imbalanced-learn库的算子,比如SMOTE、RandomUnderSampler。如果你装的TPOT版本支持额外算子,直接在配置里加上
imblearn.over_sampling.SMOTE的配置。
python复制my_config = {
'imblearn.over_sampling.SMOTE': {
'k_neighbors': [3, 5],
},
'sklearn.ensemble.RandomForestClassifier': {
'n_estimators': [100, 200],
},
}
tpot = TPOTClassifier(scoring='roc_auc', config_dict=my_config)
- 外部重采样:如果你的TPOT版本默认配置里没有imblearn算子,可以在训练前先做重采样,或者用带
class_weight='balanced'的模型算子替换默认配置。
6.3 数据泄露风险不止在预处理
用TPOT做特征选择的时候也要警惕数据泄露。TPOT作为搜索框架,它选择哪些特征、选择什么算子组合,是基于交叉验证结果来决策的。整个过程都在训练集上进行,理论上测试集没有被接触过。但如果你的特征工程里包含了从全量数据计算出来的统计特征,比如目标编码、基于全体样本的归一化统计量,这些信息一样会通过特征本身泄露到训练中。
所以TPOT能保证的是“在给定特征矩阵内的数据隔离”,不能保证“特征构造过程本身的安全性”。特征构造必须在划分训练测试集之后进行,且只能使用训练集的数据来计算特征参数。
6.4 运行时长失控:最常遇到的现实问题
我把运行时长放在最后说,因为这是TPOT劝退最多人的原因。很多初学者跑一个小示例觉得很好用,接着把同一套配置丢到几万行几十列的数据上,结果等了几个小时还没跑完。
原因不复杂:TPOT的评估量级是“流水线条数 × 交叉验证折数 × 单条流水线拟合时间”。默认配置里包含的模型有一部分很耗时,比如SVC在多类非线性核下、某些集成模型在样本量大时,拟合一次的耗时就很可观。
应对方法已经在前面提到过,这里汇总一下:
- 设置
max_time_mins,给搜索设定硬性时间上限。 - 用
config_dict移除耗时算子,比如把SVC从搜索空间里去掉。 - 减少
cv折数,从默认的5折改成3折,可以节省接近40%的时间。 - 在确保业务可接受的前提下,对训练集做降采样,先跑通流程,再用更充裕的时间跑全量数据。
7. 让TPOT从“跑得动”到“跑得快”:缓存、并行、Dask与降采样策略
7.1 memory缓存:避免重复计算
TPOT的进化过程中,很多流水线片段是重复出现的。比如“StandardScaler → RandomForest”这个结构可能在多个个体里反复出现,每次进化都要重新拟合一遍,非常浪费。TPOT提供了memory参数来缓存拟合结果,避免重复计算。
python复制from tempfile import mkdtemp
from joblib import Memory
cachedir = mkdtemp()
memory = Memory(cachedir, verbose=0)
tpot = TPOTClassifier(
generations=20,
population_size=30,
memory=memory,
# ...
)
memory可以传一个缓存目录字符串,也可以传一个joblib.Memory实例。缓存的好处分两种:单次运行内部的重复计算缓存,以及多次运行之间的缓存。如果你在同一份数据上反复调整参数做实验,指定一个固定的缓存目录,第二次运行会明显更快,因为部分流水线的拟合结果直接从缓存里读出来了。
不过要注意,缓存目录不要放在临时目录,因为临时目录重启后会清空,缓存就浪费了。建议固定一个项目内的目录。
7.2 n_jobs并行与Dask分布式
TPOT支持多核并行,n_jobs=-1会让TPOT利用所有可用的CPU核心并行评估多个流水线个体。在多核机器上,这个参数带来的加速效果非常明显,实测下来4核机器通常有接近3倍的加速比。
但对于更大的数据集或者需要多机协同的场景,单机多核也不够用。这时候可以用Dask做分布式计算。
python复制from dask.distributed import Client
import dask
client = Client(n_workers=4, threads_per_worker=2)
tpot = TPOTClassifier(
generations=20,
population_size=30,
n_jobs=1, # 使用Dask时,n_jobs设为1
use_dask=True, # 启用Dask
# ...
)
使用Dask时有一个重要细节:n_jobs要设为1,让TPOT把任务交给Dask调度器,而不是同时用joblib和Dask两套并行机制。这样反而会资源竞争,拖慢速度。
Dask的并行化比较适合单机多核无法满足、需要横向扩展到多机的情况。如果你只是单机多核,用n_jobs=-1就够了,没必要引入Dask的额外复杂度。
7.3 降采样策略:先验证再全量
对于大数据集,我个人的实操习惯是分两步走。先用降采样后的数据跑TPOT,比如从全量数据中随机抽2万到5万个样本,把generations调小,快速找到一个看起来有希望的流水线结构。然后根据这个结构,在全量数据上用固定流水线做超参优化,或者直接用TPOT导出的代码在全量数据上重新训练。
这种做法能大幅度缩短实验周期,代价是最终结果未必是全局最优。但对于业务场景来说,“在可接受的时间内拿到一个比手工搭建明显更好的流水线”,往往比“理论上最优但需要跑三天”更有实用价值。
7.4 复现性设置:固定random_state
TPOT的进化过程包含大量随机操作,包括初始种群的生成、选择、交叉、变异,再加上交叉验证时的数据划分。如果你不固定随机种子,同一份数据跑两次TPOT,得到的流水线可能完全不同。
为了保证实验的可复现性,有两个参数需要固定:
random_state:控制TPOT内部的随机过程。- 数据划分时的
random_state:在train_test_split里也固定。
这样配置之后,同一份数据、同一个参数组合,跑出来的结果是一致的。这看起来是小事,但当你需要对比不同参数配置的效果时,如果随机种子不一致,你根本分不清结果差异是参数引起的还是随机波动引起的。
8. 从跑通到落地:我把TPOT用进真实项目的几点体会
最后分享几个我在实际项目里用TPOT的感受,不一定适合所有场景,但应该能帮大家少走弯路。
TPOT最适合的场景,是你已经有一个明确的任务和一份相对干净的数据,但不确定什么样的流水线方案最合适。这时候让TPOT去搜一轮,往往能给出一个比手工尝试更好的基准方案。我经常用它来做“基线建立器”——先让TPOT跑一遍,拿到一个不错的结果作为baseline,之后手工搭建的模型如果打不过这个baseline,就说明方向有问题。
TPOT不太适合的场景是时间极紧、数据超大且特征极其复杂的生产任务。在这种场景下,直接跑TPOT很可能在等待中度过大量时间,不如基于领域知识先手工搭建一个简化流水线,用TPOT做局部优化。
另外,TPOT导出的流水线代码,拿来做预测没问题,但如果要上线到生产环境,还是要仔细审查一遍。重点看这几项:选了哪些特征、有没有敏感的预处理步骤、模型的预测延迟是否满足线上要求、是否依赖了版本特定的库。TPOT生成的代码不一定是最简洁的,但它至少是透明的,你有机会做审查,这是它比很多黑盒AutoML平台强的地方。
最后一个小技巧:TPOT跑完之后,除了看best_pipeline.py,建议也翻一下tpot.evaluated_individuals_。这里面保存了所有评估过的个体及其评分情况,能帮你了解整个搜索空间里哪些类型的流水线表现好,哪些类型毫无竞争力。这些信息用来指导后续手动建模,价值甚至比最终导出的那段代码还高。
