能否在sklearn ColumnTransformer中集成估算器并构建PMMLPipeline?
问题分析与解答
1. sklearn.compose.ColumnTransformer中能否使用估算器?
严格来说,ColumnTransformer的设计初衷是处理特征转换流程,它期望每个分支的组件是实现了fit和transform方法的转换器。不过像KMeans这类估算器其实也实现了transform方法(返回样本到各聚类中心的距离),所以从sklearn的运行逻辑上,是可以把它嵌套在ColumnTransformer的子Pipeline中的,但这会带来两个关键问题:
ColumnTransformer本身没有predict方法:它只是特征转换工具,不能直接生成预测结果,必须把转换后的特征传给后续的预测器(比如你的LinearRegression)才能完成预测。你遇到的AttributeError: 'ColumnTransformer' object has no attribute 'predict'就是这个原因。- 旧版本sklearn2pmml对这种嵌套场景支持有限:从你的报错信息来看,当前环境的sklearn2pmml无法识别
ColumnTransformer内部的KMeans估算器,导致PMML导出失败。
2. 关于ColumnTransformer.transform结果的疑问
你提到transform后得到5列(clVars处理结果)+3列(idVars),这是完全符合预期的:
- 你的子Pipeline是
StandardScaler() -> PCA(4) -> KMeans(5):KMeans.transform()默认返回的是每个样本到5个聚类中心的距离,所以这部分输出是5列,而非PCA的4列或原始clVars列(ColumnTransformer默认会用处理后的特征替换原始列,除非你设置remainder="passthrough"保留未指定的列)。 idVars通过"passthrough"直接保留,所以是3列。
3. PMMLPipeline导出失败的解决方案
针对sklearn2pmml无法识别ColumnTransformer内KMeans的问题,你可以尝试以下两种方案:
方案一:调整Pipeline结构,将KMeans移到ColumnTransformer之外
把clVars的标准化+PCA放在ColumnTransformer中,然后把KMeans作为独立步骤放在ColumnTransformer之后,让sklearn2pmml能更好地识别:
from sklearn.pipeline import PMMLPipeline, Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA from sklearn.cluster import KMeans from sklearn2pmml.preprocessing import ExpressionTransformer from sklearn.linear_model import LinearRegression pipeline = PMMLPipeline([ ("clt", ColumnTransformer([ ("cl", Pipeline([ ("std", StandardScaler()), ("pca", PCA(4)) ]), clVars), ("id", "passthrough", idVars) ])), ("kmeans", KMeans(5)), ("et", ExpressionTransformer("X[0]+X[1]")), ("lr", LinearRegression()) ])
注意:这样调整后,KMeans会对ColumnTransformer输出的所有特征(PCA结果+idVars)做聚类,如果你只想对PCA结果做聚类,可额外嵌套ColumnTransformer或用特征选择器筛选对应列。
方案二:用sklearn2pmml的TransformerWrapper包装KMeans
sklearn2pmml提供了TransformerWrapper类,可以把估算器包装成转换器,让它能被PMML导出逻辑正确识别:
from sklearn2pmml.decoration import TransformerWrapper pipeline = PMMLPipeline([ ("clt", ColumnTransformer([ ("cl", Pipeline([ ("std", StandardScaler()), ("pca", PCA(4)), ("kmeans", TransformerWrapper(KMeans(5))) ]), clVars), ("id", "passthrough", idVars) ])), ("et", ExpressionTransformer("X[0]+X[1]")), ("lr", LinearRegression()) ])
这个方案能保留你原本的Pipeline结构,同时解决PMML导出的兼容性问题。
额外建议:升级依赖版本
你的sklearn版本是0.21.2(较为老旧),建议升级到0.24.x或更高版本,同时安装对应兼容版本的sklearn2pmml(比如sklearn2pmml 0.9.x+对应sklearn 0.24+),新版本对ColumnTransformer和估算器的嵌套支持更完善。
4. 关于ColumnTransformer.predict的说明
ColumnTransformer是特征转换组件,没有predict方法是正常行为。如果你想验证整个Pipeline的预测能力,应该调用完整PMMLPipeline的predict方法,而非单独调用ColumnTransformer的predict。
内容的提问来源于stack exchange,提问作者user11671065

