2015-04-02 86 views
4

我試圖通過scikit-learn實現一個分層的文本分類器,其中一個「根」分類器將所有輸入字符串排列在一個(或多個)〜50個類別中。對於這些類別中的每一個,我都會訓練一個新的分類器,它可以解決實際的任務。SelectKBest基於(估計)的功能量

這種兩層方法的原因是訓練性能和內存問題(一個分類器應該分開> 1k類的性能不好......)。

這是我的管道看起來像這些「subclassifiers」

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到模型的大小限制在一個合理的量,但對於subclassifiers,有有時沒有足夠的輸入數據可用,所以我甚至不獲取到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兩次(提前一次,一次作爲管道的一部分)的情況下實現此行爲。

對此有何看法?

回答

3

我認爲最簡潔的選擇是在您的實現中將SelectKBest和fallback子類化到標識轉換,如果k超過輸入要素的數量,則只需調用超級實現。

+0

雖然這可能會起作用,但我想避免libraray函數的子類化以便簡化升級過程。 – Klamann 2015-04-02 12:17:17

+0

除了調用CountVectorizer兩次,我沒有看到任何其他解決方案,我想避免它。無論如何,轉換接口在sckit-learn中應該是穩定的。你爲什麼認爲升級可能是一個問題? – 2015-04-02 12:18:15

+0

你是對的,如果這是唯一的選擇,我寧願創建一個子類,但也許這裏有第三種方式... – Klamann 2015-04-02 12:25:15

5

我跟着的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" 

我嘗試添加該剪斷了他的答案,但該請求遭到拒絕你就在那兒......

+0

不錯。甚至比干擾實際轉變更乾淨。 – 2015-04-02 23:36:15

0

您可以使用SelectPercentile,如果您沒有固定數量的功能,這會更有意義。