我最近一直在尝试 sklearn 的 StackingClassifier 和 StackingRegressor,但我注意到它总是非常慢并且使用我的 CPU 效率低下。假设(只是为了这个例子)我想使用 StackingClassifier 来堆叠随机森林和 lightgbm,同时使用 lightgbm 作为最终分类器。在这种情况下,我预计运行 StackingClassifier 所需的时间大致等于运行单个随机森林所需的时间 + 运行 2 个单独的 lightgbm 的时间 + 一些小的余量(所以基本上是各部分的总和 +训练 StackingClassifier 本身的时间 + 小余量),但实际上它似乎需要数倍的时间。示例:
import numpy as np
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import StackingClassifier
import lightgbm as ltb
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import StratifiedKFold
X,y = load_iris(return_X_y=True)
cv = StratifiedKFold(n_splits=10)
lgbm = ltb.LGBMClassifier(n_jobs=4)
rf = RandomForestClassifier()
首先是 LightGBM,按照实际时间计算,在我的计算机上大约需要 140 毫秒:
%%time
scores = cross_val_score(lgbm, X, y, scoring='accuracy', cv=cv, n_jobs=4, error_score='raise')
np.mean(scores)
只是一个随机森林,这对我来说大约需要 220 毫秒:
%%time
scores = cross_val_score(rf, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
np.mean(scores)
现在是结合了这两者的 StackingClassifier。由于它基本上是运行上面两块代码+另一轮lightgbm,我预计它大约需要250+120+120=490ms,但实际上它需要大约3000ms,超过6倍长:
%%time
estimators = [
('rf', rf),
('lgbm,', lgbm)
]
clf = StackingClassifier(
estimators=estimators, final_estimator=lgbm, passthrough=True)
scores = cross_val_score(clf, X, y, scoring='accuracy', cv=cv, n_jobs=4, error_score='raise')
np.mean(scores)
我还注意到(当在更大的数据集上运行完全相同的代码时,我需要足够长的时间才能监控我的 cpu 使用情况)StackingClassifier 的 cpu 使用情况到处都是。
例如,运行单个 lightgbm 的 cpu 使用情况:
(基本上一致100%,因此有效利用CPU)
运行 lightgbm 作为 stackingclassifier 的 CPU 使用率
(到处都是,通常远不到 100%)
我是否做错了什么,导致 StackingClassifier 比各个部分的总和慢得多?
Sklearn 的 StackingClassifier 没有对估计器实现交叉验证,仅对最终的元估计器实现交叉验证。事实上,它实现了默认设置为 5 的 cross_val_predict。StackingClassifier 文档
在您的代码中,您在“cross_val_score”内调用 StackingClassifier。它基本上执行 StackingClassifier 的 cross_val_predict 次数与您设置的 cross_val_score 外部 cv 的次数相同。
这可以解释墙上时差。
您已经嵌套了交叉验证,因为在 cross_val_score 的每个折叠内,数据在 StackingClassifier 内再次分成 5 个折叠,因为它的默认 cv 值为 5 并且您没有指出。所以你可以为StackingClassifier设置cv=None来避免这种情况。 passthrough=True 还为最终估计器添加了一些计算,因为它对整个数据以及来自基本估计器的预测作为附加功能进行训练。