从数据帧形成共同出现矩阵

时间:2017-09-27 19:00:45

标签: r tidyverse

我的数据框看起来像这样:

id  val
1    a
1    b
2    a
2    c
2    d
3    a
3    a

将每一行视为一个标签val,用于带有id的观察。

我最终想要达到的目标是"共同出现"看起来像这样的矩阵,我得到每个字母与同一个字母在同一个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列数据框的问题有关。

2 个答案:

答案 0 :(得分:1)

这里是基地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))

答案 1 :(得分:0)

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

备注:

  1. 我首先将df分割为id,然后使用map_dfr中的purrrcombn函数映射到每个ID组。
  2. combn查找向量中的所有元素组合(长度(vec)选择2)并返回矩阵。
  3. _dfr末尾的
  4. map_dfr表示结果将是按行绑定列表中每个元素的数据帧。所以这实际上是do.call(rbind, lapply())
  5. mutate_all确保table保留所需的所有级别,即使列中不存在字母。
  6. 最后,由于在table步骤之后,产生了一个上三角矩阵,我将该矩阵及其转置输入pmax
  7. pmax从两个输入中找到并行最大值,并根据需要返回对称矩阵。
  8. 数据:

    df = read.table(text=  "id  val
                    1    a
                    1    b
                    2    a
                    2    c
                    2    d
                    3    a
                    3    a", header = TRUE, stringsAsFactors = FALSE)