在R中构建单词共现边缘列表

Posted

技术标签:

【中文标题】在R中构建单词共现边缘列表【英文标题】:build word co-occurence edge list in R 【发布时间】:2015-01-25 00:39:00 【问题描述】:

我有一大堆句子,我想构建单词共现的无向边列表并查看每个边的频率。我查看了tm 包,但没有找到类似的功能。有一些我可以使用的包/脚本吗?非常感谢!

注意:单词不与自身同时出现。出现两次或多次的单词在同一个句子中只与其他单词同时出现一次。

DF:

sentence_id text
1           a b c d e
2           a b b e
3           b c d
4           a e
5           a
6           a a a

输出

word1 word2 freq
a     b     2
a     c     1
a     d     1
a     e     3
b     c     2
b     d     2
b     e     2
c     d     2
c     e     1
d     e     1

【问题讨论】:

@TylerRinker 谢谢!确切地说,输出应该保持不变,因为第 5 行只有 'a' 并且在第 6 行中,'a' 不会与自身同时出现。 【参考方案1】:

这与@TylerRinker 的回答密切相关,但使用不同的工具。

library(splitstackshape)
library(reshape2)

temp <- crossprod(
  as.matrix(
    cSplit_e(d, "text", " ", type = "character", 
             fill = 0, drop = TRUE)[-1]))
temp[upper.tri(temp, diag = TRUE)] <- NA
melt(temp, na.rm = TRUE)
#      Var1   Var2 value
# 2  text_b text_a     2
# 3  text_c text_a     1
# 4  text_d text_a     1
# 5  text_e text_a     3
# 8  text_c text_b     2
# 9  text_d text_b     2
# 10 text_e text_b     2
# 14 text_d text_c     2
# 15 text_e text_c     1
# 20 text_e text_d     1

使用subgsub 可以轻松剥离“Var1”和“Var2”的“text_”部分。

【讨论】:

我喜欢。我今天在回答***.com/a/27158031/1000343 时退出了spllitstackshape,但它没有得到爱:-( 该方法看似简单直接,但 R 在最新手册中找不到函数 cSplitcSplit_ecSplit_f。我想这是因为我默认安装了 splitstackshape 1.2.0(二进制版本),而不是 1.4.2(Mac OSX 10.8.5,R 3.1.1)。我试过install.packages("splitstackshape", repos= "http://github.com/mrdwab/splitstackshape", type= "source"),但它说package ‘splitstackshape’ is not available (for R version 3.1.1) @leoce,尝试从 CRAN 安装它,但使用 type = "source"。您可能还需要对“data.table”执行相同的操作,可能在安装“splitstackshape”之前。 @leoce,要从 GitHub 安装,请尝试使用“devtools”中的install_github——类似install_github("mrdwab/splitstackshape", ref = "devel") 的东西应该会给你1.4.3。【参考方案2】:

这很复杂,所以必须有更好的方法:

dat <- read.csv(text="sentence_id, text
1,           a b c d e
2,           a b b e
3,           b c d
4,           a e", header=TRUE)


library(qdapTools); library(tidyr)
x <- t(mtabulate(with(dat, by(text, sentence_id, bag_o_words))) > 0)
out <- x %*% t(x)
out[upper.tri(out, diag=TRUE)] <- NA

out2 <- matrix2df(out, "word1") %>%
    gather(word2, freq, -word1) %>%
    na.omit() 

rownames(out2) <- NULL
out2

##    word1 word2 freq
## 1      b     a    2
## 2      c     a    1
## 3      d     a    1
## 4      e     a    3
## 5      c     b    2
## 6      d     b    2
## 7      e     b    2
## 8      d     c    2
## 9      e     c    1
## 10     e     d    1

仅基础解决方案

out <- lapply(with(dat, split(text, sentence_id)), function(x) 
    strsplit(gsub("^\\s+|\\s+$", "", as.character(x)), "\\s+")[[1]]
)

nms <- sort(unique(unlist(out)))

out2 <- lapply(out, function(x) 
    as.data.frame(table(x), stringsAsFactors = FALSE)
)

dat2 <- data.frame(x = nms)

for(i in seq_along(out2)) 
    m <- merge(dat2, out2[[i]], all.x = TRUE)
    names(m)[i + 1] <- dat[["sentence_id"]][i]
    dat2 <- m


dat2[is.na(dat2)] <- 0
x <- as.matrix(dat2[, -1]) > 0

out3 <- x %*% t(x)
out3[upper.tri(out3, diag=TRUE)] <- NA
dimnames(out3) <- list(dat2[[1]], dat2[[1]])

out4 <- na.omit(data.frame( 
        word1 = rep(rownames(out3), ncol(out3)),  
        word2 = rep(colnames(out3), each = nrow(out3)),
        freq = c(unlist(out3)),
        stringsAsFactors = FALSE)
)

row.names(out4) <- NULL

out4

【讨论】:

谢谢!你的方法可能适用于其他人未来的研究。但是,我的句子实际上是中文的,而且脚本似乎无法处理汉字。它以我无法理解的方式将所有字符变成了字母数字。 你能具体点吗?是什么部分将它们变成了字母数字? 哦,我明白了。该脚本不会将中文字符变成任何东西,它只是省略了它们。 x &lt;- t(mtabulate(with(dat, by(text, sentence_id, bag_o_words))) &gt; 0)生成的矩阵的row.names是英文单词/数字,是句子的一部分。 我什至不知道 bag_o_words 是什么,但是 +1 替代品。我已经使用“splitstackshape”中的cSplit_e作为替代方法发布了a close relative of this answer。【参考方案3】:

这是一个基本的 R 方式:

d <- read.table(text='sentence_id text
1           "a b c d e"
2           "a b b e"
3           "b c d"
4           "a e"', header=TRUE, as.is=TRUE)

result.vec <- table(unlist(lapply(d$text, function(text) 
    pairs <- combn(unique(scan(text=text, what='', sep=' ')), m=2)
    interaction(pairs[1,], pairs[2,])
)))
# a.b b.b c.b d.b a.c b.c c.c d.c a.d b.d c.d d.d a.e b.e c.e d.e 
#   2   0   0   0   1   2   0   0   1   2   2   0   3   2   1   1 

result <- subset(data.frame(do.call(rbind, strsplit(names(result.vec), '\\.')), freq=as.vector(result.vec)), freq > 0)
with(result, result[order(X1, X2),])

#    X1 X2 freq
# 1   a  b    2
# 5   a  c    1
# 9   a  d    1
# 13  a  e    3
# 6   b  c    2
# 10  b  d    2
# 14  b  e    2
# 11  c  d    2
# 15  c  e    1
# 16  d  e    1

【讨论】:

谢谢!然而,在实际数据中,可能存在两个问题。我尝试发现脚本无法删除像“哈哈”这样的 1 个单词的句子。如果一个句子有多个单词,但它们是unique 到 1(比如 'hah hah hah'),控制台也会报错。 我在这里添加了几行来处理上面的问题:***.com/review/suggested-edits/6328674,谢谢!

以上是关于在R中构建单词共现边缘列表的主要内容,如果未能解决你的问题,请参考以下文章

来自嵌套单词列表的共现矩阵

R中igraph中转置边缘列表的邻接

如何使用 R 为多路复用网络中的边缘着色

是否可以在 gephi 中分离双向边缘?

是否可以在nodejs Async(瀑布,系列等...)中构建动态任务列表

r 在Barabasi游戏中捐赠边缘以避免单身