根据(估计的)功能量选择KBest

kla*_*ann 4 python scikit-learn

我正在尝试使用scikit-learn实现分层文本分类器,其中一个"根"分类器将所有输入字符串排列在~50个类别中的一个(或多个)中.对于这些类别中的每一个,我将训练一个新的分类器,它解决了实际的任务.

这种双层方法的原因是训练性能和内存问题(应该分离> 1k类的分类器表现不佳......).

这就是我的管道对于每个"子分类器"的看法

pipeline = Pipeline([
    ('vect', CountVectorizer(strip_accents=None, lowercase=True, analyzer='char_wb', ngram_range=(3,8), max_df=0.1)),
    ('tfidf', TfidfTransformer(norm='l2')),
    ('feat', SelectKBest(chi2, k=10000)),
    ('clf', OneVsRestClassifier(SGDClassifier(loss='log', penalty='elasticnet', alpha=0.0001, n_iter=10))),
])
Run Code Online (Sandbox Code Playgroud)

现在我的问题:我正在使用SelectKBest将模型大小限制到合理的数量,但对于子分类器,有时没有足够的输入数据可用,所以我甚至没有达到10k功能限制,这会导致

(...)
  File "/usr/local/lib/python3.4/dist-packages/sklearn/feature_selection/univariate_selection.py", line 300, in fit
    self._check_params(X, y)
  File "/usr/local/lib/python3.4/dist-packages/sklearn/feature_selection/univariate_selection.py", line 405, in _check_params
    % self.k)
ValueError: k should be >=0, <= n_features; got 10000.Use k='all' to return all features.
Run Code Online (Sandbox Code Playgroud)

我不知道在没有应用的情况下我将拥有多少功能CountVectorizer,但我必须提前定义管道.我的首选解决方案是跳过这SelectKBest一步,如果k功能少于功能,但我不知道如何在不调用CountVectorizer两次的情况下实现此行为(一次提前,一次作为管道的一部分).

有什么想法吗?

kla*_*ann 5

我遵循了MartinKrämer的建议并创建了一个SelectKBest实现所需功能的子类:

class SelectAtMostKBest(SelectKBest):

    def _check_params(self, X, y):
        if not (self.k == "all" or 0 <= self.k <= X.shape[1]):
            # set k to "all" (skip feature selection), if less than k features are available
            self.k = "all"
Run Code Online (Sandbox Code Playgroud)

我试图将这个剪辑添加到他的答案但是请求被拒绝所以你有......