正确测量scikit-learn模型耗时需用timeit.repeat()多轮取最小值,每次重复前重实例化模型、固定随机种子、分离fit与predict测试,并显式指定关键参数以排除预热、缓存和数据变异干扰。

直接用 timeit 测单次 fit/predict 会受冷启动、缓存、GC 干扰,结果不可靠;真正有意义的对比必须控制变量、重复多次、排除预热干扰。
用 timeit.repeat() 跑多轮取最小值
单次测量误差大,timeit.repeat() 可执行多轮(比如 3 轮),每轮内再重复多次(比如 10 次),最后取每轮耗时最小值——这能有效过滤系统抖动和 JIT 预热影响。
- 不要用
time.time()手动包前后时间:精度低、没排除 Python 解释器开销 - 必须在每次
repeat迭代中重新实例化模型:避免上一轮fit留下的状态污染下一轮 - 数据要提前生成并固定(如用
np.random.seed(42)),否则每次X, y不同,耗时不可比
import timeit
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
X, y = make_classification(n_samples=5000, n_features=20, random_state=42)
def time_fit(model):
return timeit.repeat(
lambda: model.fit(X, y),
repeat=3,
number=10,
timer=timeit.default_timer
)
rf_time = min(time_fit(RandomForestClassifier(n_estimators=10)))
svc_time = min(time_fit(SVC()))
lr_time = min(time_fit(LogisticRegression()))
区分 fit 和 predict 耗时,别混在一起测
训练耗时(fit)和推理耗时(predict)差异极大,尤其对树模型或 SVM;合并在一个函数里测,会掩盖关键瓶颈。
-
fit耗时关注模型复杂度与数据规模:SVM 在大数据上可能卡死,RandomForest 随n_estimators线性增长 -
predict耗时更反映线上服务延迟:线性模型快,KNN 需全量距离计算,树模型取决于深度 - 务必单独封装
lambda: model.predict(X_test),且X_test大小应贴近真实部署场景(比如 1k 样本,不是 1 个)
注意模型初始化参数对耗时的隐性影响
看似相同的算法,参数不同可能导致数量级级的耗时差异。例如:
立即学习“Python免费学习笔记(深入)”;
-
RandomForestClassifier(n_estimators=100)比n_estimators=10慢约 10 倍,但默认是 100 -
SVC(kernel='rbf')训练是 O(n²~n³),换成kernel='linear'可快几个数量级 -
LogisticRegression(solver='liblinear')在小数据快,但不支持多类;solver='saga'支持 L1 但更慢 - 务必显式指定所有关键参数,不要依赖默认值——否则对比失去意义
别忽略 warm-up 和内存分配开销
第一次调用 fit 常比后续慢 2–5 倍:NumPy 初始化、OpenMP 线程池建立、scikit-learn 内部缓存填充都会拖慢首测。
- 用
timeit.repeat(repeat=3, number=10)时,每轮的 10 次执行共享同一模型实例,首测慢会影响整轮均值 → 所以取每轮最小值,而非平均值 - 如果测的是
predict,确保fit已完成且模型已“热”;否则把fit和predict放进同一个 lambda 会把训练开销算进推理里 - 大数据集下,
fit中内存分配(如构建树结构、缓存 Gram 矩阵)占时显著,这时timeit测得的是 wall-clock 时间,不是纯 CPU,这点必须心里有数
最易被忽略的是:没固定随机种子导致每次数据不同,或者忘了重置模型就反复 fit——后者会让第二次 fit 变成 warm-start 更新,完全失真。


















