cir*_*lle 1 machine-learning feature-selection scikit-learn cross-validation naivebayes
我仍然是机器学习的新手,并试图自己解决问题.我正在使用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))
Run Code Online (Sandbox Code Playgroud)
三个问题:
1)这是使用交叉验证和RFECV的正确方法吗?我特别想知道我是否有过度装配的风险.
2)我用上面的代码实现RFECV之前和之后模型的准确性几乎相同(大约78-79%),这让我很困惑.我希望通过使用RFECV来提高性能.我可能在这里错过的任何东西,或者可以做些不同的改进模型的性能?
3)您可以推荐我尝试哪些其他功能选择方法?到目前为止,我已尝试过RFE和SelectKBest,但他们都没有在模型精度方面给我任何改进.
回答你的问题:
RFECV功能选择(因此名称)中内置了交叉验证,因此您无需为此单步执行额外的交叉验证.但是,由于我了解您正在进行多项测试,因此最好进行整体交叉验证,以确保您不会过度拟合特定的列车测试分组.我想在这里提到2点:
我怀疑代码的行为与你认为的完全一样;).
# 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)
Run Code Online (Sandbox Code Playgroud)这里我们首先进行循环,有5次迭代(n_iter参数输入StratifiedShuffleSplit).然后我们走出循环,我们只使用最后的值运行所有代码train_index, test_index.所以这相当于一个列车测试分区,你可能想要有5个.如果你想让它像'正确的'交叉验证一样运行,你应该将代码移回循环中.
看到特征选择没有那么大的影响,这可能令人费解.为了更多地进行内省,您可以使用所选要素的数量来查看得分的演变(请参阅文档中的示例).
话虽如此,我认为这不是RFE的正确用例.基本上使用您的代码,您逐个消除功能,这可能需要很长时间才能运行,并且当您拥有20000个功能时没有那么多意义.
其他功能选择方法:在此提及,SelectKBest但您没有告诉我们您使用哪种方法对功能进行评分!SelectKBest将根据分数函数选择K最佳功能.我猜你正在使用默认值,但是最好知道默认值是什么;).
我会尝试SelectPercentile用chi2作为评分功能.SelectPercentile可能比SelectKBest因为你的数据集增长百分比可能比硬编码的功能更有意义.
来自文档的另一个例子就是这样(以及更多).
TfidfVectorizer而不是a CountVectorizer后跟a TfidfTransformer.这完全相同.您可以使用管道对象将分类器的不同步骤打包到一个可以运行交叉验证的对象中(我鼓励您阅读文档,它非常有用).
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))
])
Run Code Online (Sandbox Code Playgroud)然后,您就可以在管道对象上运行交叉验证,以找到alpha和百分位数的最佳组合,这对于单独的估算器来说要困难得多.
希望这有帮助,快乐学习;).