在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
使用sub
或gsub
可以轻松剥离“Var1”和“Var2”的“text_”部分。
【讨论】:
我喜欢。我今天在回答***.com/a/27158031/1000343 时退出了spllitstackshape
,但它没有得到爱:-(
该方法看似简单直接,但 R 在最新手册中找不到函数 cSplit
、cSplit_e
或 cSplit_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 <- t(mtabulate(with(dat, by(text, sentence_id, bag_o_words))) > 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中构建单词共现边缘列表的主要内容,如果未能解决你的问题,请参考以下文章