我们应该在训练/测试拆分之前还是之后预处理文本数据? [关闭]

Posted

技术标签:

【中文标题】我们应该在训练/测试拆分之前还是之后预处理文本数据? [关闭]【英文标题】:Should we preprocess text data before or after train/test split? [closed] 【发布时间】:2021-01-03 03:14:08 【问题描述】:

我阅读了许多文本监督分类教程,并为我的数据实现了 tidytext、qunateda、tm、text2vec、RTextTools。 到目前为止,我还有一个未解的谜题。关于何时标记文本数据似乎没有普遍共识。 在训练测试拆分之前还是之后?。在一篇堆栈溢出帖子中,一些人认为在拆分之前进行标记化甚至是非法的。使用 dfm_match 函数,quanteda 包看起来像是设计用于在拆分数据后进行标记化。其他人建议在预处理后进行拆分。我看过 Julia Silge 和 Emil Hvitfeldt 的精彩教程。 对我来说,如果我在拆分之前执行预处理步骤,它将为我节省很多代码行。但是,有什么风险呢?数据泄露还是什么?有没有证据比较两者在分类性能、有效性等方面?

【问题讨论】:

我投票结束这个问题,因为它与 help center 中定义的编程无关,而是关于 ML 理论和/或方法 - 请参阅介绍和 注意machine-learningtag info. 【参考方案1】:

“非法分割”?听起来很有趣(而且可能很有趣),但我从未听说过。

问题是:在什么情况下它会产生影响,以及如何产生影响?训练测试拆分对文档进行分区。在拆分之前还是之后对它们进行标记可能无关紧要,因为文档仍将包含相同的标记。

但是,一旦您从这些标记构造了一个矩阵,如果您在拆分之后 完成了此操作,那么您的模型矩阵的特征集可能与您的测试集中的特征集不同。要在测试集上进行预测,测试数据的特征必须符合训练矩阵中的特征。处理不匹配有多种可能性。

训练集中的特征,但在测试集中不存在。在 quanteda.textmodels 中,predict() 中有一个(方便!)选项以使预测矩阵自动符合训练矩阵,这意味着测试集将添加此功能但会被计算在内为零。 考虑到该特征向训练数据中添加了信息,并且它的缺失可以在测试数据中算作提供信息,这是合理的。

特征不在训练集中,但在测试集中。大多数时候,您会希望完全忽略此功能。为什么?因为在训练的模型中没有关于它的信息,所以它的效果要么是不确定的,要么完全是由于平滑。

回到这个问题,它有什么不同?我能看到的主要内容是,当一个文档特征矩阵 (dfm) 形成然后按行拆分时,训练集中的一些特征完全为零(但在测试集中不为零)。如果分割是以包含零频率特征的方式完成的,那么一些有监督的方法会对其进行平滑处理,以便包括它们的平滑值。

这是一个来自 quanteda 的示例,它使用朴素贝叶斯分类器,默认情况下对所有特征使用 +1 平滑。

让我们用两个类组成一个简单的 dfm。

library("quanteda")
## Package version: 2.1.1

txt <- c(
  d1 = "a a b b d",
  d2 = "a a a b b",
  d3 = "a b d d d",
  d4 = "a a b c d"
)
y <- c("black", "black", "white", NA)
train <- c(TRUE, TRUE, TRUE, FALSE)
test <- !train

现在先标记化,然后拆分。请注意,特征 c 对于整个三个训练集文档都为零,但如果在这个组合的 dfm 上进行索引切片,它将出现在训练集中。

dfmat1 <- tokens(txt) %>%
  dfm()
dfmat1
## Document-feature matrix of: 4 documents, 4 features (25.0% sparse).
##     features
## docs a b d c
##   d1 2 2 1 0
##   d2 3 2 0 0
##   d3 1 1 3 0
##   d4 2 1 1 1

在标记化和形成 dfm 之前完成切片时,不包括特征 c

dfmat2 <- tokens(txt[train]) %>%
  dfm()
dfmat2
## Document-feature matrix of: 3 documents, 3 features (11.1% sparse).
##     features
## docs a b d
##   d1 2 2 1
##   d2 3 2 0
##   d3 1 1 3

测试矩阵如下所示,与“黑色”相关的d 相比,与“白色”相关的a 更多。

dfmattest <- tokens(txt[test]) %>%
  dfm()
dfmattest
## Document-feature matrix of: 1 document, 4 features (0.0% sparse).
##     features
## docs a b c d
##   d4 2 1 1 1

现在,当我们训练模型并进行预测时,我们会在包含 c 时看到:

library("quanteda.textmodels")

tmod1 <- textmodel_nb(dfmat1, y)
coef(tmod1)
##        black     white
## a 0.42857143 0.2222222
## b 0.35714286 0.2222222
## d 0.14285714 0.4444444
## c 0.07142857 0.1111111
predict(tmod1, newdata = dfmattest, force = TRUE, type = "prob")
##        black     white
## d4 0.5526057 0.4473943

但不是时的结果略有不同:

tmod2 <- textmodel_nb(dfmat2, y[train])
coef(tmod2)
##       black white
## a 0.4615385  0.25
## b 0.3846154  0.25
## d 0.1538462  0.50
predict(tmod2, newdata = dfmattest, force = TRUE, type = "prob")
## Warning: 1 feature in newdata not used in prediction.
##        black     white
## d4 0.6173551 0.3826449

警告消息告诉我们测试集特征 c 没有用于预测结果,因为它不在训练集中。

所以要问的问题是,您是否希望将缺少某项功能视为提供信息?对于默认的多项式朴素贝叶斯,如果在从所有特征形成 dfm 后拆分,则可以通过平滑建模缺失,或者如果先拆分并分别创建每个 dfm,则可以忽略它。答案取决于您希望如何处理零以及它们在您的问题中的含义。它还部分取决于您的模型,因为(例如)对于伯努利朴素贝叶斯,零被认为是信息量。

【讨论】:

非常感谢您的详细解答。 Quanteda 相对容易实现,而且速度非常快。但是,我不确定如何在 quanteda 中控制参数调整。 nb 模型的性能也与我使用 tm 和 e1071 得到的不同。 谢谢。朴素贝叶斯没有参数调整,只有提供的选项。请参阅***.com/questions/54427001/… 了解 e1071 不同的原因。 感谢您在“为什么选择 R?”的精彩演讲会议。我使用正则化回归方法对文本数据进行分类。 Ridge 和 Lasso 模型在预测我的测试数据集时效果很好。在调整 lambda 和 alpha 参数时,我还尝试了一个交叉验证的弹性网络。我使用了以下编码,该模型在找到 bestTune 时效果很好。但是,预测功能失败了。 我使用了下面的代码 # Fit elastic net regression registerDoMC(cores=2) set.seed(223) cv_glmnet &lt;- train(x = dfmat_train, y = data_train$Include, method="glmnet",family="binomial", traControl=trainControl(method="cv", number=10), parallel=TRUE, tuneLength=50) predicted_value.elastic &lt;- predict(cv_glmnet, newx= dfmat_matched, s=lambda.min, type="prob") Error: Error in cbind2(1, newx) %*% nbeta: invalid class 'NA'到 dup_mMatrix_as_dgeMatrix

以上是关于我们应该在训练/测试拆分之前还是之后预处理文本数据? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

机器学习项目:在探索性数据分析之前或之后拆分训练/测试集?

在生成文档术语矩阵之前或之后拆分为测试和训练集?

在训练测试拆分之前或之后处理

训练/测试拆分之前或之后的欠采样

应该对原始数据还是拆分数据执行交叉验证分数?

Scikit-Learn One-hot-encode 在训练/测试拆分之前或之后