Quanteda:删除空文档以计算TFIDF,但将其保留在最终的DFM中
我正在尝试在数据集中计算带有许多空文档的数据集。我想在没有空文档的情况下计算TFIDF,但仍具有原始文档数量的DFM对象。
这是一个示例:
texts = c("", "Bonjour!", "Hello, how are you", "", "Good", "", "", "")
a = texts %>%
tokens(tolower=T, remove_punct=T) %>%
dfm() %>%
dfm_wordstem() %>%
dfm_remove(stopwords("en")) %>%
dfm_tfidf()
print(a, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text1 0 0 0
text2 0.90309 0 0
text3 0 0.90309 0
text4 0 0 0
text5 0 0 0.90309
text6 0 0 0
text7 0 0 0
text8 0 0 0
但是IDF受我不想要的空文档数量的影响。因此,我在类似的非空文档的子集上计算TFIDF:
a2 = texts %>%
tokens(tolower=T, remove_punct=T) %>%
dfm() %>%
dfm_subset(ntoken(.) > 0) %>%
dfm_wordstem() %>%
dfm_remove(stopwords("en")) %>%
dfm_tfidf()
print(a2, max_ndoc=10)
Document-feature matrix of: 3 documents, 3 features (66.67% sparse) and 0 docvars.
features
docs bonjour hello good
text2 0.4771213 0 0
text3 0 0.4771213 0
text5 0 0 0.4771213
我现在想具有与第一个矩阵相同格式的稀疏矩阵,但具有先前的文本值。我在stackoverflow上找到了此代码: https://stackoverflow.com/a/65635722
add_rows_2 <- function(M,v) {
oldind <- unique(M@i)
## new row indices
newind <- oldind + as.integer(rowSums(outer(oldind,v,">=")))
## modify dimensions
M@Dim <- M@Dim + c(length(v),0L)
M@i <- newind[match(M@i,oldind)]
M
}
empty_texts_idx = which(texts=="")
position_after_insertion = empty_texts_idx - 1:(length(empty_texts_idx))
a3 = add_rows_2(a2, position_after_insertion)
print(a3, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text2.1 0 0 0
text3.1 0.4771213 0 0
text5.1 0 0.4771213 0
NA.NA 0 0 0
NA.NA 0 0 0.4771213
NA.NA 0 0 0
NA.NA 0 0 0
NA.NA 0 0 0
这是我想要的已在矩阵中的适当行中添加。
问题1:我想知道是否有一种更有效的方法可以直接使用Quanteda
软件包...
问题2:...或至少不会改变一种方式DFM对象,因为a3
和a
没有相同的docvars
属性。
print(a3@docvars)
docname_ docid_ segid_
1 text2 text2 1
2 text3 text3 1
3 text5 text5 1
print(docnames(a3))
[1] "text2" "text3" "text5"
print(a@docvars)
docname_ docid_ segid_
1 text1 text1 1
2 text2 text2 1
3 text3 text3 1
4 text4 text4 1
5 text5 text5 1
6 text6 text6 1
7 text7 text7 1
8 text8 text8 1
我能够通过运行以下代码来
# necessary to print proper names in 'docs' column
new_docvars = data.frame(docname_=paste0("text",1:length(textes3)) %>% as.factor(), docid_=paste0("text",1:length(textes3))%>% as.factor(), segid_=rep(1,length(textes3)))
a3@docvars = new_docvars
# The following line is necessary for cv.glmnet to run using a3 as covariates
docnames(a3) <- paste0("text",1:length(textes3))
# seems equivalent to a3@Dimnames$docs <- paste0("text",1:length(textes3))
print(a3, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text1 0 0 0
text2 0.4771213 0 0
text3 0 0.4771213 0
text4 0 0 0
text5 0 0 0.4771213
text6 0 0 0
text7 0 0 0
text8 0 0 0
print(a3@docvars) # this is now as expected
docname_ docid_ segid_
1 text1 text1 1
2 text2 text2 1
3 text3 text3 1
4 text4 text4 1
5 text5 text5 1
6 text6 text6 1
7 text7 text7 1
8 text8 text8 1
print(docnames(a3)) # this is now as expected
[1] "text1" "text2" "text3" "text4" "text5" "text6" "text7" "text8"
更改DOCNAME(A3)的代码,可以为A3具有“正确的”格式,因为我想将A3用作我想用cv.glmet训练的型号的协变量< /code>,但是如果我不更改A3的文档名称,我会遇到错误。同样,这是进行定量的正确方法吗?我觉得手动更换docvars并不是做到这一点的正确方法,而且我在网上找不到任何东西。对此的任何见解将不胜感激。
谢谢!
I am trying to compute tfidf on a dataset with a lot of empty documents. I wanted to compute tfidf without the empty documents, but still have as an output a dfm object with the original number of documents.
Here's an example :
texts = c("", "Bonjour!", "Hello, how are you", "", "Good", "", "", "")
a = texts %>%
tokens(tolower=T, remove_punct=T) %>%
dfm() %>%
dfm_wordstem() %>%
dfm_remove(stopwords("en")) %>%
dfm_tfidf()
print(a, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text1 0 0 0
text2 0.90309 0 0
text3 0 0.90309 0
text4 0 0 0
text5 0 0 0.90309
text6 0 0 0
text7 0 0 0
text8 0 0 0
But IDF is affected by the number of empty documents, which I do not want. Therefore, I compute tfidf on the subset of non-empty documents like so :
a2 = texts %>%
tokens(tolower=T, remove_punct=T) %>%
dfm() %>%
dfm_subset(ntoken(.) > 0) %>%
dfm_wordstem() %>%
dfm_remove(stopwords("en")) %>%
dfm_tfidf()
print(a2, max_ndoc=10)
Document-feature matrix of: 3 documents, 3 features (66.67% sparse) and 0 docvars.
features
docs bonjour hello good
text2 0.4771213 0 0
text3 0 0.4771213 0
text5 0 0 0.4771213
I now want to have a sparse matrix with the same format as the first matrix, but with the previous values for the texts. I found this code on stackoverflow: https://stackoverflow.com/a/65635722
add_rows_2 <- function(M,v) {
oldind <- unique(M@i)
## new row indices
newind <- oldind + as.integer(rowSums(outer(oldind,v,">=")))
## modify dimensions
M@Dim <- M@Dim + c(length(v),0L)
M@i <- newind[match(M@i,oldind)]
M
}
empty_texts_idx = which(texts=="")
position_after_insertion = empty_texts_idx - 1:(length(empty_texts_idx))
a3 = add_rows_2(a2, position_after_insertion)
print(a3, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text2.1 0 0 0
text3.1 0.4771213 0 0
text5.1 0 0.4771213 0
NA.NA 0 0 0
NA.NA 0 0 0.4771213
NA.NA 0 0 0
NA.NA 0 0 0
NA.NA 0 0 0
Which is what I want, and the empty texts have been added at the appropriate row in the matrix.
Question 1: I was wondering if there is a more efficient way to do this directly with the quanteda
package...
Question 2: ...or at least a way that would not change the structure of the dfm object, since a3
and a
do not have the same docvars
attribute.
print(a3@docvars)
docname_ docid_ segid_
1 text2 text2 1
2 text3 text3 1
3 text5 text5 1
print(docnames(a3))
[1] "text2" "text3" "text5"
print(a@docvars)
docname_ docid_ segid_
1 text1 text1 1
2 text2 text2 1
3 text3 text3 1
4 text4 text4 1
5 text5 text5 1
6 text6 text6 1
7 text7 text7 1
8 text8 text8 1
I was able to have a "correct" format for a3 by running the following lines of code
# necessary to print proper names in 'docs' column
new_docvars = data.frame(docname_=paste0("text",1:length(textes3)) %>% as.factor(), docid_=paste0("text",1:length(textes3))%>% as.factor(), segid_=rep(1,length(textes3)))
a3@docvars = new_docvars
# The following line is necessary for cv.glmnet to run using a3 as covariates
docnames(a3) <- paste0("text",1:length(textes3))
# seems equivalent to a3@Dimnames$docs <- paste0("text",1:length(textes3))
print(a3, max_ndoc=10)
Document-feature matrix of: 8 documents, 3 features (87.50% sparse) and 0 docvars.
features
docs bonjour hello good
text1 0 0 0
text2 0.4771213 0 0
text3 0 0.4771213 0
text4 0 0 0
text5 0 0 0.4771213
text6 0 0 0
text7 0 0 0
text8 0 0 0
print(a3@docvars) # this is now as expected
docname_ docid_ segid_
1 text1 text1 1
2 text2 text2 1
3 text3 text3 1
4 text4 text4 1
5 text5 text5 1
6 text6 text6 1
7 text7 text7 1
8 text8 text8 1
print(docnames(a3)) # this is now as expected
[1] "text1" "text2" "text3" "text4" "text5" "text6" "text7" "text8"
I need to change docnames(a3) because I want to use a3 as covariates for a model I want to train with cv.glmet
, but I get an error if I don't change the document names for a3. Again, is this the correct way to proceed with quanteda? I felt like manually changing docvars was not the proper way to do it, and I could not find anything online about that. Any insights on that would be appreciated.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不知道在计算tf-idf之前删除空文档是个好主意,但是可以很容易地使用
drop_docid = false
和fill readore删除的文档,
fill = true true 因为 Quanteda 跟踪它们。由
I do not know if it is a good idea to remove empty documents before computing tf-idf, but it easy to do restore removed documents with
drop_docid = FALSE
andfill = TRUE
because quanteda keeps track of them.Created on 2022-06-16 by the reprex package (v2.0.1)