【问题标题】:SelectKBest based on (estimated) amount of features根据(估计的)特征数量选择KBest
【发布时间】:2015-06-07 08:56:23
【问题描述】:

我正在尝试使用 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 的情况下实现此行为两次(一次提前,一次作为管道)。

对此有什么想法吗?

【问题讨论】:

    标签: python scikit-learn


    【解决方案1】:

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

    【讨论】:

    • 对管道绝对有帮助。我有kbest__k: [100, 1000, 10000],但10000&gt; n_features,它会引发异常。使用SelectPercentile 就没有这个问题。
    【解决方案2】:

    我遵循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"
    

    我试图将这个片段添加到他的回答中,但请求被拒绝了,所以你在那里......

    【讨论】:

    • 不错。比弄乱实际的转换还要干净。
    【解决方案3】:

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

    【讨论】:

    • 虽然这可能可行,但我想避免库函数的子类化以简化升级过程。
    • 除了两次调用 CountVectorizer 之外,我没有看到任何其他解决方案,我想避免这种情况。无论如何,转换接口在 sckit-learn 中应该是稳定的。为什么您认为升级可能是个问题?
    • 你说得对,如果这是唯一的选择,我更愿意创建一个子类,但也许这里还有第三种方式......
    猜你喜欢
    • 1970-01-01
    • 2014-09-21
    • 2020-09-25
    • 2016-10-01
    • 2021-12-31
    • 2018-06-01
    • 2017-06-16
    • 2017-09-24
    • 2016-05-17
    相关资源
    最近更新 更多