Scikit-learn Pipeline类GLMM方案:交互项添加与GLMM集成问询
心脏病数据集下类GLMM实现与Pipeline交互特征构建方案
问题1:在Pipeline中添加分组变量与数值变量的交互特征
要生成hospital_2_age这类交互项,可通过自定义Transformer配合ColumnTransformer实现精准的特征交互,步骤如下:
实现思路
- 拆分特征类型:将数值特征(age、chol等)与分组特征(hospital)分开预处理;
- 预处理阶段:数值特征做标准化,分组特征做独热编码;
- 自定义交互生成器:提取独热后的分组特征与预处理后的数值特征,生成两两乘积的交互项,再合并到原特征集。
代码示例
import numpy as np import pandas as pd from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.base import BaseEstimator, TransformerMixin from sklearn.linear_model import LogisticRegression # 自定义交互特征生成器 class InteractionFeatureGenerator(BaseEstimator, TransformerMixin): def __init__(self, group_col_start_idx): self.group_col_start_idx = group_col_start_idx # 独热分组列的起始索引 def fit(self, X, y=None): return self def transform(self, X): # 拆分分组特征(独热后)与数值特征 group_features = X[:, self.group_col_start_idx:] numeric_features = X[:, :self.group_col_start_idx] # 生成所有分组-数值的交互项 interactions = [] for group_idx in range(group_features.shape[1]): for num_idx in range(numeric_features.shape[1]): interactions.append(group_features[:, group_idx] * numeric_features[:, num_idx]) # 合并原特征与交互项 return np.hstack([X, np.array(interactions).T]) # 定义特征列 numeric_cols = ['age', 'chol', 'trestbps', 'thalach'] group_col = ['hospital'] # 构建预处理管道 preprocessor = ColumnTransformer( transformers=[ ("num_scaler", StandardScaler(), numeric_cols), ("cat_onehot", OneHotEncoder(sparse_output=False, drop="first"), group_col) ] ) # 完整Pipeline:预处理 → 生成交互项 → 逻辑回归 full_pipeline = Pipeline([ ("preprocess", preprocessor), ("add_interactions", InteractionFeatureGenerator(group_col_start_idx=len(numeric_cols))), ("log_reg", LogisticRegression(max_iter=1000)) ]) # 拟合模型(假设df为预处理后的心脏病数据集) # full_pipeline.fit(df[numeric_cols + group_col], df["target"])
问题2:无需手动交互项的类GLMM平滑实现
由于Scikit-learn原生不支持GLMM,可通过包装Statsmodels混合模型为Sklearn兼容Estimator的方式,融入现有Pipeline工作流,自动处理分组随机效应,无需手动生成交互项。
实现思路
- 用
ColumnTransformer预处理数值特征(分组特征保留原类别,Statsmodels公式可自动处理); - 自定义Estimator包装Statsmodels的
MixedLM(支持广义线性混合模型,指定Binomial家族实现逻辑斯蒂混合模型); - 通过公式语法直接定义固定效应与随机效应,比如
(1 | hospital)表示医院级别的随机截距,(age | hospital)表示随机斜率。
代码示例
import numpy as np import pandas as pd import statsmodels.api as sm from statsmodels.regression.mixed_linear_model import MixedLM from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.preprocessing import StandardScaler from sklearn.base import BaseEstimator, ClassifierMixin # 自定义GLMM包装器,兼容Sklearn接口 class GLMMClassifier(BaseEstimator, ClassifierMixin): def __init__(self, formula, group_col): self.formula = formula self.group_col = group_col self.model = None self.results = None def fit(self, X, y): # 合并特征与目标变量,适配Statsmodels公式 df = X.copy() df["target"] = y # 构建逻辑斯蒂混合模型(Binomial家族对应logit链接) self.model = MixedLM.from_formula( formula=self.formula, data=df, groups=df[self.group_col], family=sm.families.Binomial() ) self.results = self.model.fit() return self def predict(self, X): # 预测类别(0/1) probs = self.results.predict(X) return (probs >= 0.5).astype(int) def predict_proba(self, X): # 返回两类概率 probs = self.results.predict(X) return np.vstack([1 - probs, probs]).T # 预处理管道:仅标准化数值特征,分组特征原样保留 preprocessor = ColumnTransformer( transformers=[ ("num_scaler", StandardScaler(), numeric_cols), ("cat_passthrough", "passthrough", group_col) ], remainder="drop" ) # 完整Pipeline:预处理 → GLMM分类器 glmm_pipeline = Pipeline([ ("preprocess", preprocessor), ("glmm", GLMMClassifier( formula="target ~ age + chol + trestbps + thalach + (1 | hospital)", group_col="hospital" )) ]) # 拟合模型 # glmm_pipeline.fit(df[numeric_cols + group_col], df["target"])
说明
- 公式中
(1 | hospital)表示每个医院拥有独立的随机截距,若需建模随机斜率(即不同医院的age系数不同),可改为(age | hospital); - 该方式完全替代手动生成交互项的繁琐操作,更贴合GLMM的统计逻辑。
内容的提问来源于stack exchange,提问作者Freejack
相关产品推荐
相关产品推荐

