使用部分拟合的 sklearn 投票合奏

Using sklearn voting ensemble with partial fit

有人可以告诉我如何使用部分拟合在 sklearn 中使用集成。 我不想重新训练我的模型。 或者,我们可以通过预训练模型进行集成吗? 例如,我已经看到投票分类器不支持使用部分拟合进行训练。

不幸的是,目前这在 scikit VotingClassifier 中是不可能的。

但是您可以使用http://sebastianraschka.com/Articles/2014_ensemble_classifier.html实现了 VotingClassifer)来尝试实现您自己的投票分类器,它可以采用预拟合模型。

另外我们可以看看source code here修改为我们的用途:

from sklearn.preprocessing import LabelEncoder
import numpy as np

le_ = LabelEncoder()

# When you do partial_fit, the first fit of any classifier requires 
all available labels (output classes), 
you should supply all same labels here in y.
le_.fit(y)

# Fill below list with fitted or partial fitted estimators
clf_list = [clf1, clf2, clf3, ... ]

# Fill weights -> array-like, shape = [n_classifiers] or None
weights = [clf1_wgt, clf2_wgt, ... ]
weights = None

#For hard voting:
pred = np.asarray([clf.predict(X) for clf in clf_list]).T
pred = np.apply_along_axis(lambda x:
                           np.argmax(np.bincount(x, weights=weights)),
                           axis=1,
                           arr=pred.astype('int'))

#For soft voting:
pred = np.asarray([clf.predict_proba(X) for clf in clf_list])
pred = np.average(pred, axis=0, weights=weights)
pred = np.argmax(pred, axis=1)

#Finally, reverse transform the labels for correct output:
pred = le_.inverse_transform(np.argmax(pred, axis=1))

Mlxtend 库有一个 VotingEnsemble 的实现,它允许您传入预拟合模型。例如,如果您有三个预训练模型 clf1、clf2、clf3。以下代码可以工作。

from mlxtend.classifier import EnsembleVoteClassifier
import copy
eclf = EnsembleVoteClassifier(clfs=[clf1, clf2, clf3], weights=[1,1,1], fit_base_estimators=False)

 

当设置为 false 时,EnsembleVoteClassifier 中的 fit_base_estimators 参数确保分类器不会被重新拟合。

一般来说,在寻找 sci-kit learn 没有提供的更高级的技术特性时,请将 mlxtend 作为第一个参考点。

实施投票并不难。这是我的实现:

import numpy as np 

class VotingClassifier(object):
    """ Implements a voting classifier for pre-trained classifiers"""

    def __init__(self, estimators):
        self.estimators = estimators

    def predict(self, X):
        # get values
        Y = np.zeros([X.shape[0], len(self.estimators)], dtype=int)
        for i, clf in enumerate(self.estimators):
            Y[:, i] = clf.predict(X)
        # apply voting 
        y = np.zeros(X.shape[0])
        for i in range(X.shape[0]):
            y[i] = np.argmax(np.bincount(Y[i,:]))
        return y

Mlxtend 库有一个实现工作,您仍然需要为 EnsembleVoteClassifier 调用 fit 函数。似乎 fit 函数并没有真正修改任何参数,而是检查可能的标签值。在下面的示例中,您必须给出一个数组,其中包含原始 y 中出现的所有可能值(在本例中为 1,2)到 eclf2.fit 对于 X 无关紧要。

import numpy as np
from mlxtend.classifier import EnsembleVoteClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
import copy
clf1 = LogisticRegression(random_state=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
y = np.array([1, 1, 1, 2, 2, 2])

for clf in (clf1, clf2, clf3):
    clf.fit(X, y)    
eclf2 = EnsembleVoteClassifier(clfs=[clf1, clf2, clf3],voting="soft",refit=False)
eclf2.fit(None,np.array([1,2]))
print(eclf2.predict(X))

解决方法:

VotingClassifier 检查是否设置了 estimators_ 以了解它是否适​​合,并且正在使用 estimators_ 列表中的估计器进行预测。 如果你有预训练的分类器,你可以像下面的代码一样直接把它们放在estimators_中。

但是,它也使用 LabelEnconder,因此它假定标签类似于 0,1,2...,您还需要设置 le_ 和 classes_(见下文)。

from sklearn.ensemble import VotingClassifier
from sklearn.preprocessing import LabelEncoder

clf_list = [clf1, clf2, clf3]

eclf = VotingClassifier(estimators = [('1' ,clf1), ('2', clf2), ('3', clf3)], voting='soft')

eclf.estimators_ = clf_list
eclf.le_ = LabelEncoder().fit(y)
eclf.classes_ = seclf.le_.classes_

# Now it will work without calling fit
eclf.predict(X,y)