gpt4 book ai didi

python - 使用不同文本集的参数网格搜索,用于字典创建和交叉验证

转载 作者:太空宇宙 更新时间:2023-11-03 17:54:53 26 4
gpt4 key购买 nike

我必须训练一个用于垃圾邮件检测的分类器。

我拥有的数据集。

我手头有一个带有 [text, class] 标签的电子邮件数据集。而且我还有很多没有类别标签的电子邮件。

我想做的事。

我想使用gridsearchcv()函数来估计我的模型的最佳超参数。其中一个参数与字典创建相关(例如 1-gram 或 2-gram、最小频率等)。我想要 gridsearchcv() 函数做的是在我的管道中使用整个电子邮件数据集(带标签的电子邮件 + 不带标签的电子邮件)来创建字典。但我希望它仅在带标签的电子邮件上测试结果。因此,基本上我想使用整个数据集来创建字典,并且我想仅在标记数据集上使用交叉验证来估计参数。

任何帮助将不胜感激:)

更新:

重要提示:针对 @AndreasMueller 的回答:结果会有所不同,因为我还调整了 CountVectorizer 的参数并且使用了逆文档频率。因此,我正在寻找一种方法,通过包含未标记的数据来使我的分类器更加通用。

这就是我现在所拥有的:

pipeline = Pipeline([
('features', FeatureUnion([
('words', Pipeline([
('vect', CountVectorizer()),
('frequency_transform', TfidfTransformer())
])),
('url_feature', Contains_URL_Transformer()),
('html_feature', Contains_HTML_Transformer()),
('length_feature', Text_Length_Transformer()),
('response_feature', Contains_Re_Transformer())
])),
('clf', SVC())
])

parameters = {
'features__words__vect__min_df': (1, 3, 5),
'features__words__vect__token_pattern': (r"\b[^\W\d_]+\b",),
'features__words__vect__binary': (False,),
'features__words__frequency_transform__use_idf' : (True,),
#'vect__max_features': (None, 5000, 10000, 50000),
'features__words__vect__ngram_range': ((1, 1), (1, 2)), # unigrams or bigrams
'clf__C': (1, 5, 10),
'clf__kernel': ('linear', 'rbf')
#'tfidf__use_idf': (True, False)
#'tfidf__norm': ('l1', 'l2'),
#'clf__alpha': (0.00001, 0.000001),
#'clf__penalty': ('l2', 'elasticnet'),
#'clf__n_iter': (10, 50, 80),
}

grid_search = GridSearchCV(pipeline, parameters, n_jobs=-1, verbose=1)

data_column = numpy.asarray(data['text'])

data_column = numpy.append(data_column, ['test'])

grid_search.fit(data_column, numpy.asarray(data['class']))

best_parameters = grid_search.best_estimator_.get_params()

for param_name in sorted(parameters.keys()):
print("\t%s: %r" % (param_name, best_parameters[param_name]))

但我还有unlabeld_data['text']。如何将 data['text']unlabeld_data['text'] 混合添加到管道中,以便创建字典(并估计参数)混合但要在标记数据上进行测试。问题是,当我执行 grid_search.fit() 时,它使用提供的数据集来创建字典,但我看不出有什么办法可以将所有电子邮件放在那里。

最佳答案

一个简单的解决方案强制拟合数据保持不变,而不管交叉验证数据如何:

X_all = full dataset

class MyVectorizer(sklearn.feature_extraction.text.TfidfVectorizer):
def fit(self, X, y=None):
return super(MyVectorizer, self).fit(X_all)
def fit_transform(self, X, y=None):
return super(MyVectorizer, self).fit(X_all).transform(X)

使用它代替上面的'words'子管道。

<小时/>

一个可以说不那么麻烦但更复杂的解决方案是:

  • 连接已标记和未标记的数据,设置标签后者的实例为 -1
  • 使用自定义交叉验证生成器,始终将未标记的实例保留在训练集中。
  • 在管道的后特征提取部分(此处为 SVC)使用包装器来删除未标记的数据(请注意,您不能只将其实现为 Transformer)。 (也许从 SVC 扩展更简单,有点像上面的 MyVectorizer 所做的那样,但不使用全局数据 hack。)

这种方法的一个优点是,无论 GridSearchCV 输入如何,它都适用(而不是通过全局变量注入(inject)完整数据的黑客)。

示例代码:

def semisupervised_stratified_kfold(y, *args, **kwargs):
labeled_idx = np.flatnonzero(y != -1)
unlabeled_idx = np.flatnonzero(y == -1)
for train, test in StratifiedKFold(y[labelled_idx], *args, **kwargs):
train = np.concatenate([unlabeled_idx, labeled_idx.take(train)])
test = labeled_idx.take(test)
yield train, test

from sklearn.utils.metaestimators import if_delegate_has_method
class StripUnlabelled(sklearn.base.BaseEstimator):
def __init__(self, estimator):
self.estimator = sklearn.base.clone(estimator)
def fit(self, X, y, **kwargs):
return self.estimator.fit()
@if_delegate_has_method(delegate='estimator')
def predict(self, X):
return self.estimator.predict(X)
# and similar for decision_function, predict_proba, score, etc.

然后将 GridSearchCVcv 参数设置为自定义生成器,将 StripUnlabeled 包裹在 SVC 实例周围,并在 SVC 参数名称前加上 estimator__

这实际上不会在所有数据上构建 TFIDF 模型,而是使用所有未标记数据加上标记数据的所有训练折叠。

此外,请注意,使用 Pipeline 的所有类似解决方案都将非常低效,因为在下游更改参数时不会缓存重复的工作,尽管已经提出了用于缓存部分的通用解决方案管道。

关于python - 使用不同文本集的参数网格搜索,用于字典创建和交叉验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28625456/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com