GradientBoostingClassifier 与 scikit-learn 中的 BaseEstimator?

Posted

技术标签:

【中文标题】GradientBoostingClassifier 与 scikit-learn 中的 BaseEstimator?【英文标题】:GradientBoostingClassifier with a BaseEstimator in scikit-learn? 【发布时间】:2013-07-01 12:08:37 【问题描述】:

我尝试在 scikit-learn 中使用 GradientBoostingClassifier,它的默认参数可以正常工作。但是,当我尝试用不同的分类器替换 BaseEstimator 时,它不起作用并给了我以下错误,

return y - np.nan_to_num(np.exp(pred[:, k] -
IndexError: too many indices

你有解决这个问题的办法吗?

可以使用以下 sn-ps 重新生成此错误:

import numpy as np
from sklearn import datasets
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.utils import shuffle

mnist = datasets.fetch_mldata('MNIST original')
X, y = shuffle(mnist.data, mnist.target, random_state=13)
X = X.astype(np.float32)
offset = int(X.shape[0] * 0.01)
X_train, y_train = X[:offset], y[:offset]
X_test, y_test = X[offset:], y[offset:]

### works fine when init is None
clf_init = None
print 'Train with clf_init = None'
clf = GradientBoostingClassifier( (loss='deviance', learning_rate=0.1,
                             n_estimators=5, subsample=0.3,
                             min_samples_split=2,
                             min_samples_leaf=1,
                             max_depth=3,
                             init=clf_init,
                             random_state=None,
                             max_features=None,
                             verbose=2,
                             learn_rate=None)
clf.fit(X_train, y_train)
print 'Train with clf_init = None is done :-)'

print 'Train LogisticRegression()'
clf_init = LogisticRegression();
clf_init.fit(X_train, y_train);
print 'Train LogisticRegression() is done'

print 'Train with clf_init = LogisticRegression()'
clf = GradientBoostingClassifier(loss='deviance', learning_rate=0.1,
                             n_estimators=5, subsample=0.3,
                             min_samples_split=2,
                             min_samples_leaf=1,
                             max_depth=3,
                             init=clf_init,
                             random_state=None,
                             max_features=None,
                             verbose=2,
                             learn_rate=None)
 clf.fit(X_train, y_train) # <------ ERROR!!!!
 print 'Train with clf_init = LogisticRegression() is done'

这是错误的完整回溯:

Traceback (most recent call last):
File "/home/mohsena/Dropbox/programing/gbm/gb_with_init.py", line 56, in <module>
   clf.fit(X_train, y_train)
File "/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/gradient_boosting.py", line 862, in fit
   return super(GradientBoostingClassifier, self).fit(X, y)
File "/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/gradient_boosting.py", line 614, in fit random_state)
File "/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/gradient_boosting.py", line 475, in _fit_stage
   residual = loss.negative_gradient(y, y_pred, k=k)
File "/usr/local/lib/python2.7/dist-packages/sklearn/ensemble/gradient_boosting.py", line 404, in negative_gradient
   return y - np.nan_to_num(np.exp(pred[:, k] -
   IndexError: too many indices

【问题讨论】:

【参考方案1】:

iampat 的答案的改进版本和scikit-developers 的答案的轻微修改应该可以解决问题。

class init:
    def __init__(self, est):
        self.est = est
    def predict(self, X):
        return self.est.predict_proba(X)[:,1][:,numpy.newaxis]
    def fit(self, X, y):
        self.est.fit(X, y)

【讨论】:

【参考方案2】:

根据 scikit-learn 开发人员的建议,可以使用这样的适配器来解决该问题:

def __init__(self, est):
   self.est = est
def predict(self, X):
    return self.est.predict_proba(X)[:, 1]
def fit(self, X, y):
    self.est.fit(X, y)

【讨论】:

嗨,我在 GBC 和 LR 中遇到了一个非常相似的错误:y_pred[:, k] += learning_rate * tree.predict(X).ravel() IndexError: too many indices - 试图使用您的适配器想法但无济于事,错误仍然存​​在。你有什么想法可以解决这个问题吗?【参考方案3】:

这是 iampat 的代码 sn-p 的完整且在我看来更简单的版本。

    class RandomForestClassifier_compability(RandomForestClassifier):
        def predict(self, X):
            return self.predict_proba(X)[:, 1][:,numpy.newaxis]
    base_estimator = RandomForestClassifier_compability()
    classifier = GradientBoostingClassifier(init=base_estimator)

【讨论】:

【参考方案4】:

Gradient Boosting 通常要求基学习器是一种执行数字预测的算法,而不是分类。我认为这是你的问题。

【讨论】:

感谢您的评论。如果您查看 sklearn/ensemble/gradient_boosting.py,您会发现它支持分类问题(查找 esidual = loss.negative_gradient(y, y_pred, k=k)) 梯度提升本质上是一种回归算法。它可以适应具有适当损失函数的分类。我没有时间阅读他们所有的代码,但这并不意味着它没有使用回归器来执行分类。最小二乘损失函数使用相同的方法。我会先尝试另一个非线性回归器,看看问题是否确实是你应该使用回归算法。我从未见过有人将梯度提升与非回归算法一起使用。

以上是关于GradientBoostingClassifier 与 scikit-learn 中的 BaseEstimator?的主要内容,如果未能解决你的问题,请参考以下文章