【问题标题】:SciKit Learn feature selection and cross validation using RFECVSciKit Learn 使用 RFECV 进行特征选择和交叉验证
【发布时间】:2015-11-13 14:20:39
【问题描述】:

我对机器学习还是很陌生,并且试图自己解决问题。我正在使用 SciKit 学习并拥有一个包含大约 20,000 个特征(n_features=20,000)的推文数据集。到目前为止,我的准确率、召回率和 f1 分数都达到了 79% 左右。我想使用 RFECV 进行特征选择并提高模型的性能。我已经阅读了 SciKit 学习文档,但对如何使用 RFECV 仍然有些困惑。

这是我目前的代码:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.naive_bayes import MultinomialNB
from sklearn.cross_validation import StratifiedShuffleSplit
from sklearn.cross_validation import cross_val_score
from sklearn.feature_selection import RFECV
from sklearn import metrics

# cross validation
sss = StratifiedShuffleSplit(y, 5, test_size=0.2, random_state=42)
for train_index, test_index in sss:
    docs_train, docs_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

# feature extraction
count_vect = CountVectorizer(stop_words='English', min_df=3, max_df=0.90, ngram_range=(1,3))
X_CV = count_vect.fit_transform(docs_train)

tfidf_transformer = TfidfTransformer()
X_tfidf = tfidf_transformer.fit_transform(X_CV)

# Create the RFECV object
nb = MultinomialNB(alpha=0.5)

# The "accuracy" scoring is proportional to the number of correct classifications
rfecv = RFECV(estimator=nb, step=1, cv=2, scoring='accuracy')

rfecv.fit(X_tfidf, y_train)
X_rfecv=rfecv.transform(X_tfidf)

print("Optimal number of features : %d" % rfecv.n_features_)

# train classifier
clf = MultinomialNB(alpha=0.5).fit(X_rfecv, y_train)

# test clf on test data

X_test_CV = count_vect.transform(docs_test)
X_test_tfidf = tfidf_transformer.transform(X_test_CV)
X_test_rfecv = rfecv.transform(X_test_tfidf)

y_predicted = clf.predict(X_test_rfecv)

#print the mean accuracy on the given test data and labels

print ("Classifier score is: %s " % rfecv.score(X_test_rfecv,y_test))

三个问题:

1) 这是使用交叉验证和 RFECV 的正确方法吗?我特别想知道我是否存在过度拟合的风险。

2) 我用上面的代码实现 RFECV 之前和之后的模型的准确率几乎相同(大约 78-79%),这让我感到困惑。我希望通过使用 RFECV 来提高性能。我可能在这里遗漏了什么或者可以采取不同的方式来提高我的模型的性能?

3) 您还可以推荐我尝试哪些其他特征选择方法?到目前为止,我已经尝试过 RFE 和 SelectKBest,但它们在模型准确性方面都没有给我任何改进。

【问题讨论】:

    标签: machine-learning scikit-learn cross-validation feature-selection naivebayes


    【解决方案1】:

    回答您的问题:

    1. 在 RFECV 功能选择中内置了一个交叉验证(因此得名),因此您实际上不需要为这一步进行额外的交叉验证。但是,由于我了解您正在运行多个测试,因此最好进行整体交叉验证,以确保您不会过度拟合特定的训练测试拆分。我想在这里提两点:

      1. 我怀疑代码的行为与您认为的完全一样;)。

           # cross validation
           sss = StratifiedShuffleSplit(y, 5, test_size=0.2, random_state=42)
           for train_index, test_index in sss:
               docs_train, docs_test = X[train_index], X[test_index]
               y_train, y_test = y[train_index], y[test_index]
           # feature extraction
           count_vect = CountVectorizer(stop_words='English', min_df=3, max_df=0.90, ngram_range=(1,3))
           X_CV = count_vect.fit_transform(docs_train)
        

      这里我们首先遍历循环,它有 5 次迭代(StratifiedShuffleSplit 中的n_iter 参数)。然后我们退出循环,我们只需使用train_index, test_index 的最后一个值运行您的所有代码。所以这相当于一个单独的训练测试拆分,您可能打算拥有 5 个。如果您希望它像“正确”交叉验证一样运行,您应该将代码移回循环中。

      1. 您担心过度拟合:确实,在“寻找最佳方法”时,存在我们将选择最有效的方法的风险……仅在我们正在测试该方法的小样本上。 这里的最佳做法是进行第一次训练测试拆分,然后仅使用训练集执行交叉验证。当您认为自己找到了一些东西时,可以“谨慎地”使用测试集,以确保您获得的分数是一致的并且不会过度拟合。
        您可能会丢弃 30% 的数据(您的测试集),但这绝对值得。
    2. 看到特征选择没有那么大的影响可能令人费解。要进一步反省,您可以查看分数的演变与所选特征的数量(请参阅the example from the docs)。
      话虽如此,我认为这不是 RFE 的正确用例。基本上,使用您的代码,您正在一个一个地消除功能,这可能需要很长时间才能运行,并且在您拥有 20000 个功能时没有多大意义。

    3. 其他特征选择方法:这里您提到SelectKBest,但您没有告诉我们您使用哪种方法对特征进行评分! SelectKBest根据评分函数选择 K 个最佳特征。我猜您使用的是默认值,这没问题,但最好了解默认值的作用;)。

      我会尝试使用SelectPercentilechi2 作为评分函数。 SelectPercentile 可能比 SelectKBest 更方便一点,因为如果您的数据集增长一个百分比可能比硬编码的特征数量更有意义。
      Another example from the docs 就是这样做的(甚至更多)。

    补充说明:

    • 您可以使用TfidfVectorizer 而不是CountVectorizer 后跟TfidfTransformer。这是严格等价的。
    • 您可以使用pipeline object 将分类器的不同步骤打包到一个可以运行交叉验证的对象中(我鼓励您阅读文档,它非常有用)。

      from sklearn.feature_selection import chi2_sparse
      from sklearn.feature_selection import SelectPercentile
      from sklearn.pipeline import Pipeline
      from sklearn.feature_extraction.text import TfidfVectorizer
      
      pipeline = Pipeline(steps=[
          ("vectorizer", TfidfVectorizer(stop_words='English', min_df=3, max_df=0.90, ngram_range=(1,3))),
          ("selector", SelectPercentile(score_func=chi2, percentile=70)),
          ('NB', MultinomialNB(alpha=0.5))
      ])
      

    然后,您就可以对管道对象运行交叉验证,以找到 alpha 和百分位数的最佳组合,这对于单独的估算器要困难得多。

    希望这会有所帮助,祝您学习愉快;)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-05
      • 2020-07-10
      • 2013-11-08
      • 2017-04-12
      • 2021-03-26
      • 2021-10-25
      • 2018-02-24
      相关资源
      最近更新 更多