为什么置于Pipeline中的RandomForestClassifier训练速度大幅变慢
核心原因
- 嵌套并行开销:你同时给
ColumnTransformer和RandomForestClassifier设置了n_jobs=10,当组合在Pipeline中时,joblib的并行调度会产生嵌套进程调用,大数据量下进程间数据拷贝、调度的开销被指数级放大,小数据量下该开销占比低所以差距不明显,完全匹配你观察到的现象。 - 稀疏矩阵处理效率低:
OneHotEncoder默认输出稀疏矩阵,ColumnTransformer默认稀疏度阈值为0.3,高稀疏度下会保留稀疏矩阵格式,而随机森林训练时处理稀疏矩阵的速度远低于稠密数组。 - 预处理器输出的内存布局/类型不优:默认输出的float64类型数组内存占用更高,多进程训练时数据拷贝开销更大。
解决方案
- 移除
ColumnTransformer的n_jobs=10配置,改成单进程执行预处理。预处理是一次性操作,170万样本的编码单进程执行耗时极低,不会影响整体效率,同时彻底避免嵌套并行的开销。 - 强制输出稠密矩阵:给所有
OneHotEncoder添加参数sparse_output=False(scikit-learn 1.2+版本,旧版本用sparse=False),或者给ColumnTransformer添加参数sparse_threshold=0,强制预处理输出稠密numpy数组。 - 优化数据类型:在Pipeline的预处理环节最后添加类型转换步骤,把数据转成float32降低内存占用,示例:
from sklearn.preprocessing import FunctionTransformer preprocessing = ColumnTransformer( [ ('binary', OneHotEncoder(drop='if_binary', sparse_output=False), binary_category_cols), ('complete', OneHotEncoder(sparse_output=False), complete_category_cols), ('inc_cat', OneHotEncoder(drop=[-9]*len(incomplete_category_cols), sparse_output=False), incomplete_category_cols), ('inc_ord', OneHotEncoder(drop=[-9]*len(incomplete_ordinal_cols), sparse_output=False), incomplete_ordinal_cols), ('cmp_ord', OrdinalEncoder(), complete_ordinal_cols) ], verbose=True, sparse_threshold=0 ) clf = Pipeline( [ ('preprocess', preprocessing), ('to_float32', FunctionTransformer(lambda x: x.astype('float32', copy=False))), ('classifier', rf_clf) ] )
- 如果你后续要跑
permutation_importance,可以设置n_jobs和随机森林的n_jobs不冲突,避免再次出现嵌套并行问题;如果特征维度不高,也可以提前做一次预处理把数据存为稠密数组,再单独训练模型跑特征重要性,整体效率更高。
内容的提问来源于stack exchange,提问作者Denis
相关产品推荐
相关产品推荐

