如何使用管道对嵌入 OneVsRestClassifier 的估计器进行网格搜索

How to gridsearch an estimator embeded in OneVsRestClassifier using Pipeline

我正在使用 GridSearchCV 进行模型选择和超参数调整。从最初的实验来看,结果证明带有 rdf 内核的 SVC 具有最好的性能。问题是样本太慢(200K+)。使用 OneVsRestClassifier 可以并行化 SVC (n_jobs)。但是,当我使用 Pipeline 同时测试多个估算器时,gridsearchcv 不适用于此嵌入式估算器。

pipe = Pipeline([('clf', SVC())]) # Placeholder Estimator

# Candidate learning algorithms and their hyperparameters
search_space = [{'clf': [OneVsRestClassifier(SVC(tol=0.1, gamma='scale', probability=True), n_jobs=-1],
                 'clf__kernel': ['rbf', 'linear'],
                 'clf__C': [1, 10, 100]},

                {'clf': [LogisticRegression(tol=0.1, penalty='l1', solver='saga', multi_class='multinomial', n_jobs=8)], 
                 'clf__C': [1, 10, 100]},

                {'clf': [RandomForestClassifier(n_jobs=8)],
                 'clf__n_estimators': [50, 100, 200, 300, 400],
                 'clf__max_depth': [10, 20, 30],
                 'clf__min_samples_leaf': [1, 2, 4],
                 'clf__min_samples_split': [2, 5, 10]},

                {'clf': [MultinomialNB()],
                 'clf__alpha': [0.1, 0.5, 1]}]

gs = GridSearchCV(pipe, search_space, cv=skf, scoring='accuracy', verbose=10)

我遇到错误

Invalid Parameter __kernel

但是根据GridSearch for an estimator inside a OneVsRestClassifier,这个方法应该可行。我认为是管道搞砸了,因为它基本上在 OneVsRestClassifier 之上添加了另一层。我该如何为这个嵌套估计器执行 gridsearchcv?

照原样,管道在 OneVsRestClassifier 中查找参数 kernel,找不到(不出所料,因为模块没有这样的参数),并引发错误。由于您实际上想要 SVC 的参数 kernel(以及随后的 C),您应该更深入:将 search_space 的前 3 个条目更改为:

{'clf': [OneVsRestClassifier(SVC(tol=0.1, gamma='scale', probability=True), n_jobs=-1],
 'clf__estimator__kernel': ['rbf', 'linear'],
 'clf__estimator__C': [1, 10, 100]}

你应该没问题。

然而,无论错误如何,您使用此方法的理由:

The problem with that is it is too slow (200K+) sample. Using OneVsRestClassifier can parallelize SVC (n_jobs).

不正确。 OneVsRestClassifier 将并行化 n_classes 个不同的 SVC 估计量的拟合, 而不是 SVC 本身。实际上,您试图通过在其周围包裹其他东西(此处 OneVsRestClassifier)来避免瓶颈(SVC),这会增加其自身的额外计算复杂性,只是为了(不出所料)再次在你.

我们可以用虚拟数据的一些时间来证明这一点——让我们尝试一个比较现实的数据集,其中包含 10K 个样本、5 个特征和 3 个 类:

from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.datasets import make_classification

X, y = make_classification(n_samples = 10000, n_features=5, n_redundant=0, n_informative=5,
                             n_classes = 3, n_clusters_per_class=1, random_state=42)

%timeit for x in range(10): SVC().fit(X,y)
# 1 loop, best of 3: 7.72 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC()).fit(X, y)
# 1 loop, best of 3: 21.1 s per loop

好吧,那是你的基准差异;现在设置 n_jobs=-1 有帮助:

%timeit for x in range(10): OneVsRestClassifier(SVC(), n_jobs=-1).fit(X, y)
# 1 loop, best of 3: 19 s per loop

但是,不出所料,它只针对未并行化的 OneVsRestClassifier 这样做, 而不是 SVC 本身相关。

随着功能的增加,差异越来越大 & 类;不去你的完整案例,这里是有 10 个特征和 5 类(相同数量的样本,10K)的情况:

X1, y1 = make_classification(n_samples = 10000, n_features=10, n_redundant=0, n_informative=10,
                             n_classes = 5, n_clusters_per_class=1, random_state=42)

%timeit for x in range(10): SVC().fit(X1,y1)
# 1 loop, best of 3: 10.3 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC()).fit(X1, y1)
# 1 loop, best of 3: 30.7 s per loop

%timeit for x in range(10): OneVsRestClassifier(SVC(), n_jobs=-1).fit(X1, y1)
# 1 loop, best of 3: 24.9 s per loop

所以,我强烈建议您在这里重新考虑您的方法(和您的目标)。

(Google Colab 中的所有时间)。