使SVM在python中运行得更快

Abh*_*tia 47 python svm scikit-learn

在python中使用以下代码用于svm:

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
iris = datasets.load_iris()
X, y = iris.data, iris.target
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
clf.fit(X, y)
proba = clf.predict_proba(X)
Run Code Online (Sandbox Code Playgroud)

但这需要花费大量时间.

实际数据维度:

train-set (1422392,29)
test-set (233081,29)
Run Code Online (Sandbox Code Playgroud)

我怎样才能加快速度(平行或其他方式)?请帮忙.我已经尝试过PCA和下采样.

我有6节课.编辑:发现http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html 但我希望进行概率估计,而且对于svm来说似乎并非如此.

编辑:

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC,LinearSVC
from sklearn.linear_model import SGDClassifier
import joblib
import numpy as np
from sklearn import grid_search
import multiprocessing
import numpy as np
import math

def new_func(a):                              #converts array(x) elements to (1/(1 + e(-x)))
    a=1/(1 + math.exp(-a))
    return a

if __name__ == '__main__':
    iris = datasets.load_iris()
    cores=multiprocessing.cpu_count()-2
    X, y = iris.data, iris.target                       #loading dataset

    C_range = 10.0 ** np.arange(-4, 4);                  #c value range 
    param_grid = dict(estimator__C=C_range.tolist())              

    svr = OneVsRestClassifier(LinearSVC(class_weight='auto'),n_jobs=cores) ################LinearSVC Code faster        
    #svr = OneVsRestClassifier(SVC(kernel='linear', probability=True,  ##################SVC code slow
    #   class_weight='auto'),n_jobs=cores)

    clf = grid_search.GridSearchCV(svr, param_grid,n_jobs=cores,verbose=2)  #grid search
    clf.fit(X, y)                                                   #training svm model                                     

    decisions=clf.decision_function(X)                             #outputs decision functions
    #prob=clf.predict_proba(X)                                     #only for SVC outputs probablilites
    print decisions[:5,:]
    vecfunc = np.vectorize(new_func)
    prob=vecfunc(decisions)                                        #converts deicision to (1/(1 + e(-x)))
    print prob[:5,:]
Run Code Online (Sandbox Code Playgroud)

编辑2:用户 3914041的答案产生非常差的概率估计.

小智 82

如果您希望尽可能多地使用SVC并在完整数据集上进行训练,则可以使用在数据子集上训练的SVC集合来减少每个分类器的记录数(这显然对复杂性有二次影响).Scikit支持BaggingClassifier包装器.与单个分类器相比,这应该给你相似(如果不是更好)的准确性,训练时间少得多.也可以使用n_jobs参数将各个分类器的训练设置为并行运行.

或者,我也会考虑使用随机森林分类器 - 它本身支持多类分类,它很快并且在min_samples_leaf适当设置时提供相当好的概率估计.

我对虹膜数据集进行了快速测试,测试结果包括10个SVC,每个数据集都被烧毁了100次,每个SVC都训练了10%的数据.它比单个分类器快10倍以上.这些是我在笔记本电脑上得到的数字:

单SVC:45秒

合奏SVC:3s

随机森林分类器:0.5s

请参阅下面我用于生成数字的代码:

import time
import numpy as np
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC

iris = datasets.load_iris()
X, y = iris.data, iris.target

X = np.repeat(X, 100, axis=0)
y = np.repeat(y, 100, axis=0)
start = time.time()
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
clf.fit(X, y)
end = time.time()
print "Single SVC", end - start, clf.score(X,y)
proba = clf.predict_proba(X)

n_estimators = 10
start = time.time()
clf = OneVsRestClassifier(BaggingClassifier(SVC(kernel='linear', probability=True, class_weight='auto'), max_samples=1.0 / n_estimators, n_estimators=n_estimators))
clf.fit(X, y)
end = time.time()
print "Bagging SVC", end - start, clf.score(X,y)
proba = clf.predict_proba(X)

start = time.time()
clf = RandomForestClassifier(min_samples_leaf=20)
clf.fit(X, y)
end = time.time()
print "Random Forest", end - start, clf.score(X,y)
proba = clf.predict_proba(X)
Run Code Online (Sandbox Code Playgroud)

如果要确保每个记录仅用于训练一次BaggingClassifier,则可以将bootstrap参数设置为False.

  • 这是一个很棒的方法!:我在 F1 Score 上得到了类似的结果;当没有 BaggingClassifier 运行时,需要 4d 3h 27 分钟,但使用 BaggingClassifier 运行需要 31 分钟 8 秒 (2认同)

ldi*_*rer 17

SVM分类器不容易扩展.从文档,关于复杂性sklearn.svm.SVC.

拟合时间复杂度大于二次方与样本数量,这使得难以缩放到具有多个10000个样本的数据集.

在scikit-learn中你svm.linearSVC可以更好地扩展.显然它可以处理你的数据.

或者你可以选择另一个分类器.如果你想要概率估计,我建议采用逻辑回归.逻辑回归还具有不需要概率校准来输出"适当"概率的优点.

编辑:

我不知道linearSVC复杂性,最后我在用户指南中找到了信息:

还要注意,对于线性情况,线性实现在LinearSVC中使用的算法比其基于libsvm的SVC对应物更有效,并且可以几乎线性地扩展到数百万个样本和/或特征.

通过linearSVC检查此链接获取概率.它只是与我上面链接的概率校准指南的几个链接,并包含估计概率的方法.即:

    prob_pos = clf.decision_function(X_test)
    prob_pos = (prob_pos - prob_pos.min()) / (prob_pos.max() - prob_pos.min())
Run Code Online (Sandbox Code Playgroud)

请注意,如果没有校准,估算可能会很差,如链接所示.

  • 如果您有特定问题可以随意提出,但对于这个概念,我将无法比我在帖子中提供的链接做得更好. (2认同)

ser*_*inc 7

在最佳答案中简要提到了它; 这里是代码:要做到这一点,最快的方法就是通过n_jobs参数:替代线

clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
Run Code Online (Sandbox Code Playgroud)

clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'), n_jobs=-1)
Run Code Online (Sandbox Code Playgroud)

这将使用您计算机上的所有可用CPU,同时仍然执行与以前相同的计算.


And*_*ler 7

您可以使用kernel_approximation模块将SVM扩展为大量此类样本.