Scikit-learn中LinearSVC高C值时训练缓慢的问题及优化咨询
问题:LinearSVC在C=10时训练极慢的原因及加速方案
我正在完成《ISLR》(第一版)的习题,用Python实现SVM章节的代码,针对OJ数据集训练分类器——训练样本数800,独热编码后约22个特征。使用LinearSVC时,惩罚参数C值较小训练速度很快,但C=10时训练了30分钟还没完成。
我的理解是:C值大时支持向量数量少,选择训练点作为支持向量的方式更多,所以训练慢?这属于预期行为吗?另外有没有加速代码的替代方案?
最小可复现代码:
import numpy as np import pandas as pd from sklearn import svm from sklearn.preprocessing import OneHotEncoder from sklearn.svm import LinearSVC from sklearn.model_selection import train_test_split oj = pd.read_csv("https://github.com/makbigc/ISLR/blob/master/datasets/OJ.csv?raw=TRUE", index_col=0) oj.Store7 = oj.Store7.map({"No":0, "Yes":1}) enc = OneHotEncoder(handle_unknown='ignore') encodedStoreID = enc.fit_transform(oj[["StoreID"]]) oj[["StoreID_1","StoreID_2","StoreID_3","StoreID_4"]] = encodedStoreID[:,:-1].toarray() X = oj.loc[:,oj.columns.isin(['Purchase','StoreID','STORE']) == False] y = oj.loc[:,"Purchase"] X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=800/X.shape[0], random_state=42) model = LinearSVC(C=10, random_state=0).fit(X_train, y_train)
一、是否属于预期行为?
是,这属于LinearSVC的预期行为,核心原因如下:
- LinearSVC默认采用对偶坐标下降法(
dual=True),当C值越大,对分类错误的惩罚越重,模型会尽可能拟合所有样本,此时需要找到更精确的分隔超平面,对偶问题的收敛速度会显著变慢。 - 你的理解存在偏差:C值大时,模型对误分类的容忍度极低,会倾向于选择更多支持向量——因为要尽可能让所有样本被正确分类,更多样本会落在间隔边界上或边界内,成为支持向量。而对偶问题的计算复杂度和支持向量数量正相关,因此C越大,训练速度越慢。
- 此外,当样本数远大于特征数时(你的场景是800样本vs22特征),对偶方法原本就不如原始优化方法高效,C值放大时这个问题会更明显。
二、加速训练的替代方案
1. 切换到原始优化问题
直接设置dual=False,强制LinearSVC使用原始优化问题,这是针对当前场景最有效的加速手段,修改后训练会在几秒内完成:
model = LinearSVC(C=10, random_state=0, dual=False).fit(X_train, y_train)
2. 调整收敛阈值
如果不需要极致的模型精度,可以适当调大收敛阈值tol(默认1e-4),减少迭代次数:
model = LinearSVC(C=10, random_state=0, dual=False, tol=1e-3).fit(X_train, y_train)
3. 用SGDClassifier替代
使用SGDClassifier实现线性SVM(损失函数选hinge,惩罚项选l2),它采用随机梯度下降,适合大规模数据集,训练速度更快:
from sklearn.linear_model import SGDClassifier # alpha等价于1/(C*n_samples),这里C=10、n_samples=800,alpha=1/(10*800)=0.000125 model = SGDClassifier(loss='hinge', penalty='l2', alpha=0.000125, random_state=0).fit(X_train, y_train)
4. 特征标准化
LinearSVC对特征尺度敏感,标准化后能让优化过程更稳定、收敛更快:
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) model = LinearSVC(C=10, random_state=0, dual=False).fit(X_train_scaled, y_train)
内容的提问来源于stack exchange,提问作者user1237300
相关产品推荐
相关产品推荐

