使用R中的apply将矩阵转换为配对列表?

时间:2016-10-25 16:25:48

标签: r matrix apply

我的矩阵类似于下面的矩阵但更大。

vec <- c(0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0)
M <- matrix(vec, nrow = 4, byrow = TRUE)
colnames(M) <- rownames(M) <- LETTERS[1:4]

   A, B, C, D
A, 0, 1, 1, 0
B, 0, 0, 1, 1
C, 1, 0, 0, 0
D, 0, 1, 1, 0

最终,我想要一个矩阵或data.frame,每次连续调用都有一个值时,我最终会得到一个rowname,列名对。因此,给定上面的矩阵,我最终得到下面的矩阵或数据框:

A,B
A,C
B,C
B,D
C,A
D,B
D,C

我可以使用循环和expand.grid来做到这一点,但这似乎是我应该能够使用apply函数。例如,我可以像这样分开:

tmp <- apply(M, 1, function(x) colnames(M)[which(x > 0)])

给了我

$A
[1] "B" "C"
$B
[1] "C" "D"
$C
[1] "A"
$D
[1] "B" "C"

如果这很容易,那么我是否还可以将单元格中的数字(对于0以上的单元格)包含在第三列中?

4 个答案:

答案 0 :(得分:4)

igraph方法

library(igraph)  
as_data_frame(graph_from_adjacency_matrix(M, weighted = TRUE))

graph_from_adjacency_matrix()将矩阵作为输入并返回图形。使用weighted=TRUE将非零值作为权重返回。 as_data_frame返回具有相关属性的边缘列表(在本例中为权重)

所以对你的例子来说,

as_data_frame(graph_from_adjacency_matrix(M, weighted = TRUE))
#   from to weight
# 1    A  B      1
# 2    A  C      1
# 3    B  C      1
# 4    B  D      1
# 5    C  A      1
# 6    D  B      1
# 7    D  C      1

答案 1 :(得分:3)

了解@ Frank关于melt的建议,这是使用该方法和dplyr的一种方法:

library(reshape2)
library(dplyr)

M2 <- M %>%
  melt(.) %>%
  transmute(pair = paste(Var1, Var2, sep = ","),
            value = value) %>%
  filter(value > 0)

结果的顺序与您展示的顺序不同,但我不清楚这对您是否重要。

答案 2 :(得分:3)

您不一定需要使用apply()循环。这是基础R中的一个想法,它使用which()来查找相关索引,然后进行一些简单的提取和组合。

wM <- which(M > 0, arr.ind = TRUE)
matrix(sort(paste(rownames(wM), colnames(M)[wM[,2]], sep = ",")))
#      [,1] 
# [1,] "A,B"
# [2,] "A,C"
# [3,] "B,C"
# [4,] "B,D"
# [5,] "C,A"
# [6,] "D,B"
# [7,] "D,C"

或者,您可以使用rowcol代替which

M0 <- M > 0
paste(rownames(M)[row(M)[M0]], colnames(M)[col(M)[M0]], sep = ",")
# [1] "C,A" "A,B" "D,B" "A,C" "B,C" "D,C" "B,D"

答案 3 :(得分:2)

bind(new TypeLiteral<List<String>>(){}).to(list)