使用sklearn2pmml构建PMML管道,分类列预处理遇阻求助
解决sklearn2pmml自定义分类变量映射的PMML管道问题
你的核心问题是直接将普通函数作为管道步骤,不符合sklearn的估计器接口,导致sklearn2pmml无法序列化并转换为PMML。正确的做法是把自定义预处理逻辑封装成符合sklearn接口的Transformer类,这样才能被PMMLPipeline识别和处理。
可行解决方案
通过继承sklearn.base.BaseEstimator和sklearn.base.TransformerMixin,实现自定义预处理转换器,让它兼容sklearn管道和sklearn2pmml的导出逻辑。
完整可运行代码
from sklearn.model_selection import train_test_split from sklearn.datasets import make_classification from sklearn.tree import DecisionTreeClassifier from sklearn.base import BaseEstimator, TransformerMixin import pandas as pd import numpy as np from sklearn2pmml.pipeline import PMMLPipeline from sklearn2pmml import sklearn2pmml # 固定随机种子 BIRTHDAY_SEED = 1995 nrows, cols = 1000, 5 X, y = make_classification(n_samples=nrows, n_features=cols, n_informative=2, n_redundant=3, n_classes=2, shuffle=True, random_state=BIRTHDAY_SEED) X, y = pd.DataFrame(X), pd.Series(y) X["cat_variable"] = np.random.choice(["a","b","c"], size=len(X), random_state=BIRTHDAY_SEED) # 封装自定义分类变量映射转换器 class CategoryMapper(BaseEstimator, TransformerMixin): def __init__(self): # 定义分类到数值的映射规则 self.mapping = { "a": 1.5, "b": 2.0, "c": 1.97 } def fit(self, X, y=None): # 转换器不需要训练,直接返回自身 return self def transform(self, X): # 复制输入数据避免修改原始数据 X_copy = X.copy() # 应用映射,未知类别返回-1 X_copy["cat_variable"] = X_copy["cat_variable"].map(self.mapping).fillna(-1) return X_copy # 构建PMML管道,包含预处理步骤和模型 pmml_pipeline = PMMLPipeline([ ("category_mapping", CategoryMapper()), ("decisiontree", DecisionTreeClassifier(random_state=BIRTHDAY_SEED)) ]) # 训练整个管道 pmml_pipeline.fit(X, y) # 导出为PMML文件 sklearn2pmml(pmml_pipeline, "example_pipeline_pmml.pmml", with_repr=True)
关键说明
为什么要封装成类?
- sklearn管道的每个步骤必须是实现了
fit()和transform()方法的估计器,普通函数不满足这个要求。 - sklearn2pmml只能识别符合sklearn接口的组件,才能将其转换为PMML对应的预处理节点。
- sklearn管道的每个步骤必须是实现了
自定义转换器的核心逻辑
fit()方法:由于映射规则是固定的,不需要从数据中学习,直接返回自身即可。transform()方法:复制输入数据避免副作用,使用map()应用自定义映射,未知类别用fillna(-1)填充。
管道训练与导出
- 直接训练整个
PMMLPipeline,而不是先预处理数据再训练模型,这样管道会记录完整的预处理逻辑,确保导出的PMML包含所有必要步骤。
- 直接训练整个
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

