Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用不同文本集进行参数网格搜索以创建字典和交叉验证_Python_Email_Pandas_Scikit Learn_Text Classification - Fatal编程技术网

Python 使用不同文本集进行参数网格搜索以创建字典和交叉验证

Python 使用不同文本集进行参数网格搜索以创建字典和交叉验证,python,email,pandas,scikit-learn,text-classification,Python,Email,Pandas,Scikit Learn,Text Classification,我必须训练一个用于垃圾邮件检测的分类器 我拥有的数据集。 我手头有一个标有[文本,类]的电子邮件数据集。 我也有很多没有班级标签的电子邮件 我想做什么。 我想使用gridsearchcv()函数估计模型的最佳超参数。其中一个参数与字典创建有关(如1-gram或2-gram、最小频率等)。我想要gridsearchcv()函数做的是使用管道中countvectorier的整个电子邮件数据集(带标签的电子邮件+不带标签的电子邮件)来创建字典。但我想让它只在有标签的电子邮件上测试结果。所以,基本上,我

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

我拥有的数据集。

我手头有一个标有
[文本,类]
的电子邮件数据集。 我也有很多没有班级标签的电子邮件

我想做什么。

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

任何帮助都将受到欢迎:)

更新:

重要提示:解决@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]))

但是我还有
未启用的数据['text']
。如何将
data['text']
unlabled_data['text']
的组合添加到管道中,以便从该组合创建字典(并估计参数),但在标记的数据上测试它。问题是,当我执行
grid\u 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)周围使用包装器来删除未标记的数据(注意,您不能仅使用 将其实现为一个
    转换器
    )。(也许从SVC扩展更简单,有点像上面的
    MyVectorizer
    所做的,但不使用全局数据黑客。)
这种方法的一个优点是,它适用于任何
GridSearchCV
输入(而不是通过全局变量注入完整数据)

示例代码:

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.
然后将
GridSearchCV
cv
参数设置为自定义生成器,在
SVC
实例周围环绕
StripUnlabeled
,并在SVC参数名称前面加上
estimator\uuuu

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


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

您选择了哪一部分?试过什么吗?在线文档很漂亮clear@EdChum,我被卡在管道部分。我更新了我的问题。如果你能指出我能找到答案的文档,我会非常高兴。我认为这是一个非常合理的问题,我能想到的最好的解决方案是有点令人失望。在scikit learn通用邮件列表中提出这个问题可能是值得的。@joeln,尽管如此,谢谢你。为了更清楚地说明这一点,您应该编辑该问题以突出显示您的参数搜索包括CountVectorizer参数这一事实。我认为这个想法是使用从更大的语料库派生的TFIDF模型。我不确定,因为他使用的是count vectorizer,然后是TFIDF transformer。应用于CountVectorizer的解决方案不会改变任何内容。为什么不在数据上安装一个矢量器,然后在创建矢量器时使用固定的词汇表呢?因为OP也想合并来自整个语料库的文档频率统计信息,但仅限于由网格搜索参数确定的词汇表。嗯,对,我不知道他在搜索矢量器参数,too@joeln对这正是我想做的。