我正在处理一个分类问题,需要预测文本数据的类别。我需要对分类模型进行超参数调优,为此我考虑使用 GridSearchCV
。由于我的数据不平衡,我还需要使用 StratifiedKFold
。我知道在多类分类的情况下,GridSearchCV
内部会使用 StratifiedKFold
。
我在这里阅读到,在使用 TfidfVectorizer
时,我们对训练数据应用 fit_transform
,而对测试数据仅应用 transform
。
这是我使用 StratifiedKFold
所做的操作。
skf = StratifiedKFold(n_splits=5, random_state=5)for train_index, test_index in skf.split(X, y): iteration = iteration+1 print(f"Iteration number {iteration}") X_train, y_train = X.iloc[train_index], y.iloc[train_index] X_test, y_test = X.iloc[test_index], y.iloc[test_index] train_tfid = tfidf_vectorizer.fit_transform(X_train.values.astype('U')) test_tfid = tfidf_vectorizer.transform(X_test.values.astype('U')) svc_model = linear_model.SGDClassifier() svc_model.fit(train_tfid, y_train.values.ravel())
我得到的准确率/F1 得分并不理想,因此考虑使用 GridSearchCV 进行超参数调优。在 GridSearchCV 中,我们这样做
c_space = np.logspace(-5, 8, 15) param_grid = {'C': c_space} # 实例化逻辑回归分类器 logreg = LogisticRegression() # 实例化 GridSearchCV 对象 logreg_cv = GridSearchCV(logreg, param_grid, cv = 5) logreg_cv.fit(X, y)
据我所知,logreg_cv.fit(X, y)
会在内部将 X 分成 X_train
、X_test
k 次,然后进行预测以给出最佳估计器。
在我的情况下,X 应该是什么?如果是经过 fit_transform
处理后的 X,那么当 X 内部被分成训练和测试数据时,测试数据已经经历了 fit_transform
,但理想情况下它应该只进行 transform 处理。
我的担忧是在我的情况下,如何在 GridSearchCV
内部控制只对训练数据应用 fit_transform
,而对测试数据(验证数据)只应用 transform。
因为如果它在内部对整个数据应用 fit_transform
,这不是一个好的做法。
回答:
这正是你应该在 GridSearchCV
中使用 Pipeline
的场景。首先,创建一个包含所需步骤的管道,如数据预处理、特征选择和模型。一旦你对这个管道调用 GridSearchCV
,它将只在训练折叠上进行数据处理,然后与模型一起拟合。
阅读这里以了解更多关于 sklearn 中的模型选择模块的信息。
from sklearn.datasets import fetch_20newsgroupsfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.pipeline import Pipelinefrom sklearn.ensemble import RandomForestClassifierfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_split, GridSearchCVimport numpy as npcats = ['alt.atheism', 'sci.space']newsgroups_train = fetch_20newsgroups(subset='train', remove=('headers', 'footers', 'quotes'), categories=cats)X, y = newsgroups_train.data, newsgroups_train.targetX_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.1, stratify=y)my_pipeline = Pipeline([ ('vectorizer', CountVectorizer(stop_words='english')), ('clf', LogisticRegression())])parameters = {'clf__C': np.logspace(-5, 8, 15)}grid_search = GridSearchCV(my_pipeline, param_grid=parameters, cv=10, n_jobs=-1, scoring='accuracy')grid_search.fit(X_train, y_train)print(grid_search.best_params_)# {'clf__C': 0.4393970560760795}grid_search.score(X_test, y_test)# 0.8981481481481481