根据(估计的)特征量选择KBest



我正试图用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))),
])

现在我的问题是:我使用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.

我不知道如果不应用CountVectorizer,我会有多少功能,但我必须提前定义管道。我的首选解决方案是跳过SelectKBest步骤,如果无论如何都有少于k的功能,但如果不调用CountVectorizer两次(提前调用一次,作为管道的一部分调用一次),我不知道如何实现这种行为。

对此有什么想法吗?

我听从Martin Krä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"

我试着把这个片段添加到他的回答中,但请求被拒绝了,所以你来了。。。

我认为最干净的选项是子类SelectKBest,并在实现中回退到身份转换,如果k超过了输入特性的数量,否则只调用超级实现。

您可以使用SelectPercentile,如果您没有固定数量的功能,这将更有意义。

相关内容

  • 没有找到相关文章