【问题标题】:Count identical row values for each pair of columns to create network graph计算每对列的相同行值以创建网络图
【发布时间】:2016-04-27 20:21:22
【问题描述】:

我有这样的数据:

dat <- data.frame(
  music = c("classical", "jazz", "baroque", "electronic", "ambient"),
  john = c(1,1,0,1,1),
  jeff = c(1,0,0,1,0),
  jane = c(0,1,1,0,0)
)

       music john jeff jane
1  classical    1    1    0
2       jazz    1    0    1
3    baroque    0    0    1
4 electronic    1    1    0
5    ambient    1    0    0

并且想要绘制列上个人之间的重叠 - 他们多久在同一行中都有 1?如果我能得到这个data.frame

result <- data.frame(person1 = c("john", "john", "jeff"), person2 = c("jeff", "jane", "jane"), overlap = c(2, 1, 0))

  person1 person2 overlap
1    john    jeff       2
2    john    jane       1
3    jeff    jane       0

我可以创建我想要的图表:

library(igraph)
g <- graph.data.frame(result, directed = FALSE)
plot(g, edge.width = result$overlap * 3)

但我正在努力转换数据以计算每对列之间的逐行重叠。我该怎么做?

【问题讨论】:

  • 尝试使用m &lt;- crossprod(as.matrix(dat[-1]),然后使用graph_from_adjacency_matrix(根据您的结果,您可能需要将对角线设置为零 diag(m)
  • @user20650 这是一个完美的答案;我认为你应该把它正式化。

标签: r igraph


【解决方案1】:

可能更简单的方法是通过取叉积来创建图的邻接矩阵。然后,您可以将其直接读入 igraph。

library(igraph)

# Take the crossproduct: assumes unique music types in each row
# otherwise aggregate terms
m <- crossprod(as.matrix(dat[-1]))

# You could remove the diagonal terms here
# although it is useful to see the sum for each individual
# You can also remove it in igraph, as below
# diag(m) <- 0

# Create graph
# The weights are stored in E(g)$weight
g <- graph_from_adjacency_matrix(m, mode="undirected", weighted = TRUE)

# Remove edge loops
g <- simplify(g)

【讨论】:

    【解决方案2】:

    也许您想尝试不同的相似度/距离度量,例如 Russel/Roa、Jaccard 等。我的意思是:0 和 0 也可以解释为相似度。无论如何,这是另一种方法:

    library(proxy)
    m <- (1-as.matrix(dist( t(dat[, -1]), method = "Russel")))*nrow(dat)
    m[lower.tri(m, T)] <- NA
    (res <- setNames(reshape2::melt(m, na.rm=T), c("p1", "p2", "ol")))
    #     p1   p2 ol
    # 4 john jeff  2
    # 7 john jane  1
    # 8 jeff jane  0
    

    【讨论】:

      【解决方案3】:

      以下适用于您的示例:

      # build name matrix
      nameMat <- t(combn(names(dat[,-1]), 2))
      # pre-allocate count vector
      overLap <- integer(nrow(nameMat))
      
      # loop through name combos
      for(i in 1:nrow(nameMat)) {
        overLap[i] <- sum(rowSums(dat[, nameMat[i,]]) == 2)
      }
      # construct data.frame
      df <- data.frame("person1"=nameMat[,1], "person2"=nameMat[,2], "overLap"=overLap)
      

      如果您不喜欢for 循环,可以使用sapply 来获取重叠计数:

      overLap <- sapply(1:(nrow(nameMat)), 
                        function(i) sum(rowSums(dat[, nameMat[i,]]) == 2))
      

      根据@user20650 的建议,您还可以使用combn 计算重叠:

      overLap <- combn(dat[-1], 2, FUN=function(i) sum(rowSums(i)==2))
      

      一个long计算重叠的方法如下: overLap

      这个较长的版本有一个优点,它可以推广到这些度量在李克特量表上的情况(指示亲和力强度)。在 5 分制的情况下,可以将 c(1,1) 改为 c(3,3) 来检验无差异或 c(5,5)。如果兴趣是对立的观点,例如 c(1,5),则必须操纵和复制 nameMat:

      newNameMat <- rbind(nameMat, cibind(nameMat[,2], nameMat[,1])
      

      并在此矩阵上执行计算。将这些操作封装到一个可以计算李克特量表组合的任何成对比较的函数中并不难。

      【讨论】:

      • 对于您的最后一次计算,您可以在组合中执行此操作..combn(dat[-1], 2, FUN=function(x) sum(rowSums(x)==2)),但您也许可以一起完成...t(combn(dat[-1], 2, FUN=function(x) c(names(x), sum(rowSums(x)==2))))(尽管我确信这可以简化)
      • 感谢@user20650 的提示。我以前没有以这种方式使用过combn。我将您的第一个 comb 建议添加到我的回答中。
      猜你喜欢
      • 2022-10-21
      • 1970-01-01
      • 2014-01-14
      • 1970-01-01
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      • 2011-11-14
      相关资源
      最近更新 更多