在输入数组上运行带有削减的分类器(python)

时间:2019-02-24 14:39:26

标签: python arrays input scikit-learn classification

我想知道是否可以通过接受输入数据切割的调用来运行分类器(例如RandomForestClassifier,GradientBoostingClassifier)。

为使问题更清楚,我们要运行

gbcl = GradientBoostingClassifier(n_estimators=100,
                                  learning_rate=1.0,
                                  max_depth=5,
                                  random_state=1).fit(X_train, y_train)

但仅使用X_train[:,3] > 0的事件。

除了创建新的输入数组之外,还有其他方法吗?

2 个答案:

答案 0 :(得分:2)

在scikit-learn的上下文中,您必须创建一个新数据,例如X_train_new = X_train[X_train[:,3] > 0]y_train_new = y_train[X_train[:,3] > 0],或者,如果要避免“用杂散数组填充代码”,则传递切片的数据直接使用fit方法:

model.fit(X_train[X_train[:, 3] > 0], y_train[X_train[:, 3] > 0])

b = (X_train[:, 3] > 0)
model.fit(X_train[b], y_train[b])

答案 1 :(得分:1)

不可能使用标准的sklearn功能,但是您可以创建一个可以轻松完成所需操作的类(我同意它更具可读性)。

我个人会选择这样的东西:

class SlicingClassifier:
    """Create classifiers of slice data.

    Parameters
    ----------
    classifier : sklearn-compatible classifier
            Classifier with sklearn-compatible interface. Needs fit method.
    slices : array-like[bool] or generator
            List of Boolean numpy arrays able to slice features and targets.
            Can be a generator returning slices.
    """

    def __init__(self, classifier, slices):
        self.classifier_ = classifier
        self.slices_ = slices
        self.models_ = []

    def fit(self, X, y):
        for index_slice in self.slices_:
            self.models_.append(self.classifier_.fit(X[index_slice], y[index_slice]))

        return self

    # You may want to make this a list, but it's more memory-efficient as gen        
    def predict(self, X):
        for model in self.models_:
            yield model.predict(X)

如果需要,您可以轻松地使用多个分类器扩展此方法,使用不同的predict方法fit_transform,使API与sklearn兼容,依此类推。

如果只关心每个数据子集的预测,那么(从内存的角度来看)好的加法可以像函数fit_transform一样生成:

def fit_transform_generator(self, X, y):
    for index_slice in self.slices_:
        yield self.classifier_.fit_transform(X[index_slice], y[index_slice])

示例调用将遵循这些原则,并将使您免于切片数组的丑陋临时创建。

classifier = SlicingClassifier(
    GradientBoostingClassifier(
        n_estimators=100, learning_rate=1.0, max_depth=5, random_state=1
    ),
    # Go with your slices however you want, could use generator
    # function as well, even better IMO
    slices=[X > 0, (X ** 3) > X, X[:, 3] != 0],
)

classifier.fit(X, y)
predictions = classifier.predict(X)

重要

那些切片不会复制数组,它们使用视图和引用,因此不需要额外的内存(对原始X进行切片的数组除外)。

切片作为生成器

您也可以使用生成器对象,而不是像List那样传递切片(对于许多切片索引,您应该使用此方法)。

提供示例以消除混乱:

def slices_generator(X, stop, start=0, step=1):
    for i in range(start, stop, step):
        yield X < i

classifier = SlicingClassifier(
    GradientBoostingClassifier(
        n_estimators=100, learning_rate=1.0, max_depth=5, random_state=1
    ),
    slices=slices_generator(X, 1000),
)