代码之家  ›  专栏  ›  技术社区  ›  Abhishek Bhatia

让SVM在python中运行得更快

  •  57
  • Abhishek Bhatia  · 技术社区  · 9 年前

    使用 密码 下面是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)
    

    但这需要大量的时间。

    实际数据维度 :

    train-set (1422392,29)
    test-set (233081,29)
    

    我如何加快速度(并行或其他方式)?请帮忙。 我已经尝试过PCA和降采样。

    我有6节课。 编辑: 建立 http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.SGDClassifier.html 但我希望得到概率估计,而支持向量机似乎不是这样。

    编辑:

    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,:]
    

    编辑2: 用户3914041的回答给出了非常差的概率估计。

    5 回复  |  直到 9 年前
        1
  •  128
  •   Alexander Bauer    9 年前

    如果您希望尽可能多地使用SVC并在整个数据集上进行训练,可以使用在数据子集上训练的SVC集合来减少每个分类器的记录数(这显然对复杂性有二次影响)。Scikit通过 BaggingClassifier 包装。与单个分类器相比,这应该会给你类似(如果不是更好)的准确度,而且训练时间要短得多。也可以使用 n_jobs 参数

    或者,我也会考虑使用Random Forest分类器——它本机支持多类分类,速度快,并且在以下情况下可以给出很好的概率估计 min_samples_leaf 被适当地设置。

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

    单个SVC:45s

    集成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)
    

    如果要确保每个记录仅用于 袋装分类器 ,您可以设置 bootstrap 参数设置为False。

        2
  •  22
  •   ldirer    9 年前

    SVM分类器不那么容易缩放。从文档中,关于 sklearn.svm.SVC .

    拟合时间复杂度大于 使其难以扩展到数据集的样本 大约10000个样本。

    在scikit学习 svm.linearSVC 这可以更好地缩放。 显然它可以处理你的数据。

    或者,您可以使用另一个分类器。如果你想要概率估计,我建议你进行逻辑回归。 Logistic回归还具有不需要 probability calibration 以输出“正确”概率。

    编辑:

    我不知道 linearSVC 最后,我在 user guide :

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

    线性SVC 退房 this link 。它与我上面链接的概率校准指南相距仅几个链接,并包含一种估计概率的方法。 即:

        prob_pos = clf.decision_function(X_test)
        prob_pos = (prob_pos - prob_pos.min()) / (prob_pos.max() - prob_pos.min())
    

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

        3
  •  8
  •   serv-inc    6 年前

    您可以使用 the kernel_approximation module 将SVM放大到像这样的大量样本。

        4
  •  7
  •   serv-inc    7 年前

    它在最上面的答案中被简要提及;这是代码:最快的方法是通过 the n_jobs parameter :更换管路

    clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'))
    

    具有

    clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, class_weight='auto'), n_jobs=-1)
    

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

        5
  •  2
  •   Mahmuda Keya    4 年前

    对于大型数据集,考虑使用LinearSVC或SGDClassifier,可能在Nystroem变压器之后。

    https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html