修改cSplit_e函数以考虑多个值

3

我知道 "splitstackshape" 中的 "cSplit_e" 可以将一个列中的多个值转换为带有二进制值的单独列。我正在处理一个文本问题,计算 tf-idf 并不需要在一列下拥有所有唯一的值。例如,

docname   ftype                        doc_text
    1      mw               hello, hi, how, are, you, hello
    2      gw                       hi,yo,man
    3      mw                     woha,yo, yoman

DPUT(df)

   structure(list(docname = 1:3, ftype = c("mw", "gw", "mw"), doc_text = structure(1:3, .Label = c("hello, hi, how, are, you, hello", 
"hi,yo,man", "woha,yo, yoman"), class = "factor")), .Names = c("docname", 
"ftype", "doc_text"), class = "data.frame", row.names = c(NA, 
-3L))

对于上述示例,如果我们考虑doc-1,则cSplit_e将把doc_text转换为5个单独的列,当“hello”出现两次时,它们的值为“1”。有没有一种方法修改此函数以考虑重复值?
实质上,这是我想要实现的:给定一个数据框
docname ftype doc_text 1 mw hello,hi,how,are,you,hello 2 gw hi,yo,man 3 me woha,yo,yoman
我希望基于用","分隔的列值将doc_text转换为多个列并获取它们各自的频率。结果应该是:
docname ftype are hello hi how man woha yo yoman you
     1   mw    1     2  1   1   0    0  0     0   1
     2   gw    0     0  1   0   1    0  1     0   0
     3   mw    0     0  0   0   0    1  1     1   0

如果有人知道如何使用 "splitstackshape" 或其他方法来完成此操作,我会非常感慕。最终目的是计算 tf-idf。

谢谢。


V2 of "splitstackshape"发布时,我会添加一个答案,因为cSplit_e()现在已经被修改为具有“计数”模式,可以按照您的期望进行操作。 - A5C1D2H2I1M1N2O1R2T1
2个回答

3
我们可以用mtabulate在按'doc_text'拆分后完成此操作。
library(qdapTools)
cbind(df[1], mtabulate(strsplit(as.character(df$doc_text), ",\\s*")))
#   docname are hello hi how man woha yo yoman you
#1       1   1     2  1   1   0    0  0     0   1
#2       2   0     0  1   0   1    0  1     0   0
#3       3   0     0  0   0   0    1  1     1   0

另一个选择是 tidyverse

library(tidyverse)
separate_rows(df, doc_text) %>% #split to long format
           group_by(docname, doc_text) %>% #group by variables
           tally() %>% #get the frequency
           spread(doc_text, n, fill=0) #reshape to wide

或者按照@Frank的建议
library(splitstackshape)
cSplit(df, "doc_text", ",", "long")[, dcast(.SD, docname ~ doc_text)]

2
感谢 @akrun 和 Frank。 - syebill

2

通过一些 文本挖掘

docs <- gsub('[[:punct:]]+', ' ', as.character(df$doc_text))
library(tm)
corpus <- Corpus(VectorSource(docs))

# compute Term Frequencies
as.matrix(DocumentTermMatrix(corpus, control = list(wordLengths=c(2,Inf))))
#     Terms
#Docs are hello hi how man woha yo yoman you
#   1   1     2  1   1   0    0  0     0   1
#   2   0     0  1   0   1    0  1     0   0
#   3   0     0  0   0   0    1  1     1   0

# compute Tf-Idf scores
as.matrix(DocumentTermMatrix(corpus, control = list(wordLengths=c(2,Inf), weighting=weightTfIdf)))
#         Terms
#Docs       are     hello         hi       how       man      woha        yo     yoman`       you
#   1 0.2641604 0.5283208 0.09749375 0.2641604 0.0000000 0.0000000 0.0000000 0.0000000 0.2641604
#   2 0.0000000 0.0000000 0.19498750 0.0000000 0.5283208 0.0000000 0.1949875 0.0000000 0.0000000
#   3 0.0000000 0.0000000 0.00000000 0.0000000 0.0000000 0.5283208 0.1949875 0.5283208 0.0000000

根据你的第一行,这将把像“hello world”这样的多个单词视为单独的值。如果是这样的话,你可能需要提到这个警告。 - Frank
2
@Frank 是的,这是“词袋”表示法,因此不考虑n>1n-grams,例如短语。 - Sandipan Dey
@Sandipan。我看到你已经去掉了标点符号以删除“,”,但如果文本中有应该成为单词一部分的有意义的标点符号呢?我应该省略第一步并遵循其余步骤吗?此外,您能否解释一下“wordLengths = c(2,Inf)”是用于指定文档中单词的最小和最大长度吗? - syebill
默认情况下,2,Inf 是单词最小和最大长度(DocumentTermMatrix 忽略所有长度小于 3 的单词)。在进行 DocumentTermMatrix 计算之前,去除标点符号和空格是一种标准做法。如果跳过第一行,则可能会得到带有额外空格的单词;如果将去除标点符号作为文本预处理步骤,则可能会得到连接在一起的单词,这可能是不可取的。 - Sandipan Dey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接