从数据帧形成共现矩阵
Forming a co-occurence matrix from a data frame
我有一个看起来像这样的数据框:
id val
1 a
1 b
2 a
2 c
2 d
3 a
3 a
将每一行想象成一个标签,val,它被赋予了一些带有 id 的观察。
我最终想要得到的是一个 "co-occurence" 矩阵,它看起来像这样,我计算每个字母与其他字母在同一 ID 中出现的次数:
a b c d
a 1 1 1 1
b 1 0 0 0
c 1 0 0 1
d 1 0 1 0
我一直在绞尽脑汁寻找方法,但到目前为止一无所获。有什么提示吗?最好使用 tidyverse 工具,但此时也可以使用其他选项。
编辑:在这种情况下,链接为可能重复的问题的解决方案不起作用。我不确定为什么,但我怀疑这与具有 3 列数据框的问题有关。
这是一个基于 R 的解决方案。不太优雅但似乎有效
temp = data.frame(do.call(cbind, lapply(split(df, df$id), function(a)
combn(a$val, 2))), stringsAsFactors = FALSE)
sapply(sort(unique(df$val)), function(rows)
sapply(sort(unique(df$val)), function(cols)
sum(sapply(temp, function(x)
identical(sort(x), sort(c(rows, cols)))))))
# a b c d
#a 1 1 1 1
#b 1 0 0 0
#c 1 0 0 1
#d 1 0 1 0
或 igraph
temp = t(do.call(cbind, lapply(split(df, df$id), function(a) combn(a$val, 2))))
library(igraph)
as.matrix(get.adjacency(graph(temp, directed = FALSE)))
# a c b d
#a 1 1 1 1
#c 1 0 0 1
#b 1 0 0 0
#d 1 1 0 0
数据
df = structure(list(id = c(1L, 1L, 2L, 2L, 2L, 3L, 3L),
val = c("a", "b", "a", "c", "d", "a", "a")),
.Names = c("id", "val"),
class = "data.frame",
row.names = c(NA, -7L))
dplyr
+purrr
的解决方案:
library(dplyr)
library(purrr)
df %>%
split(.$id) %>%
map_dfr(function(x){
t(combn(x$val, 2)) %>%
data.frame(stringsAsFactors = FALSE)
}) %>%
mutate_all(funs(factor(., levels = c("a", "b", "c", "d")))) %>%
table() %>%
pmax(., t(.))
结果:
X2
X1 a b c d
a 1 1 1 1
b 1 0 0 0
c 1 0 0 1
d 1 0 1 0
备注:
- 我首先将
df
拆分为 id
,然后使用 purrr
中的 map_dfr
将 combn
函数映射到每个 id 组。
combn
查找向量(length(vec) 选择 2)和 returns 矩阵中元素的所有组合。
_dfr
在 map_dfr
的末尾意味着结果将是一个按行绑定列表中每个元素的数据框。所以这实际上是 do.call(rbind, lapply())
。
mutate_all
确保 table
保留所需的所有级别,即使列中不存在字母。
- 最后,由于在
table
步骤之后,生成了一个上三角矩阵,我将该矩阵及其转置输入 pmax
pmax
从两个输入中找到平行最大值,并根据需要 returns 一个对称矩阵。
数据:
df = read.table(text= "id val
1 a
1 b
2 a
2 c
2 d
3 a
3 a", header = TRUE, stringsAsFactors = FALSE)
我有一个看起来像这样的数据框:
id val
1 a
1 b
2 a
2 c
2 d
3 a
3 a
将每一行想象成一个标签,val,它被赋予了一些带有 id 的观察。
我最终想要得到的是一个 "co-occurence" 矩阵,它看起来像这样,我计算每个字母与其他字母在同一 ID 中出现的次数:
a b c d
a 1 1 1 1
b 1 0 0 0
c 1 0 0 1
d 1 0 1 0
我一直在绞尽脑汁寻找方法,但到目前为止一无所获。有什么提示吗?最好使用 tidyverse 工具,但此时也可以使用其他选项。
编辑:在这种情况下,链接为可能重复的问题的解决方案不起作用。我不确定为什么,但我怀疑这与具有 3 列数据框的问题有关。
这是一个基于 R 的解决方案。不太优雅但似乎有效
temp = data.frame(do.call(cbind, lapply(split(df, df$id), function(a)
combn(a$val, 2))), stringsAsFactors = FALSE)
sapply(sort(unique(df$val)), function(rows)
sapply(sort(unique(df$val)), function(cols)
sum(sapply(temp, function(x)
identical(sort(x), sort(c(rows, cols)))))))
# a b c d
#a 1 1 1 1
#b 1 0 0 0
#c 1 0 0 1
#d 1 0 1 0
或 igraph
temp = t(do.call(cbind, lapply(split(df, df$id), function(a) combn(a$val, 2))))
library(igraph)
as.matrix(get.adjacency(graph(temp, directed = FALSE)))
# a c b d
#a 1 1 1 1
#c 1 0 0 1
#b 1 0 0 0
#d 1 1 0 0
数据
df = structure(list(id = c(1L, 1L, 2L, 2L, 2L, 3L, 3L),
val = c("a", "b", "a", "c", "d", "a", "a")),
.Names = c("id", "val"),
class = "data.frame",
row.names = c(NA, -7L))
dplyr
+purrr
的解决方案:
library(dplyr)
library(purrr)
df %>%
split(.$id) %>%
map_dfr(function(x){
t(combn(x$val, 2)) %>%
data.frame(stringsAsFactors = FALSE)
}) %>%
mutate_all(funs(factor(., levels = c("a", "b", "c", "d")))) %>%
table() %>%
pmax(., t(.))
结果:
X2
X1 a b c d
a 1 1 1 1
b 1 0 0 0
c 1 0 0 1
d 1 0 1 0
备注:
- 我首先将
df
拆分为id
,然后使用purrr
中的map_dfr
将combn
函数映射到每个 id 组。 combn
查找向量(length(vec) 选择 2)和 returns 矩阵中元素的所有组合。_dfr
在map_dfr
的末尾意味着结果将是一个按行绑定列表中每个元素的数据框。所以这实际上是do.call(rbind, lapply())
。mutate_all
确保table
保留所需的所有级别,即使列中不存在字母。- 最后,由于在
table
步骤之后,生成了一个上三角矩阵,我将该矩阵及其转置输入pmax
pmax
从两个输入中找到平行最大值,并根据需要 returns 一个对称矩阵。
数据:
df = read.table(text= "id val
1 a
1 b
2 a
2 c
2 d
3 a
3 a", header = TRUE, stringsAsFactors = FALSE)