在矩阵中用列表替换奇异值

3

给定矩阵

test <- structure(list(X1 = c(3L, 0L, 3L, 1L, 2L, 2L, 1L, 2L, 2L, 3L), 
X2 = c(2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), X3 = c(0L, 
0L, 3L, 0L, 2L, 2L, 3L, 0L, 0L, 2L), X4 = c(1L, 1L, 1L, 0L, 
3L, 1L, 3L, 1L, 1L, 1L), X5 = c(3L, 3L, 1L, 3L, 1L, 3L, 2L, 
3L, 3L, 3L), X6 = c(3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L
), X7 = c(2L, 2L, 2L, 3L, 2L, 2L, 3L, 2L, 2L, 2L), X8 = c(3L, 
0L, 1L, 0L, 1L, 1L, 3L, 0L, 0L, 1L), X9 = c(3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L)), .Names = c("X1", "X2", "X3", "X4", 
"X5", "X6", "X7", "X8", "X9"), row.names = c("1", "2", "3", "4", 
"5", "6", "7", "8", "9", "10"), class = "data.frame")

我试图将每个“1”替换为数字序列c(0,0,1),将2替换为c(0,1,0),将3替换为(1,0,1),将0替换为(0,0,0)。矩阵中的每个值都应替换为这三个二进制值序列之一。生成矩阵的nrow应为nrow(test)*3。显然,我尝试使用索引test[test == 1] <- c(0,0,1),但这会返回错误消息"rhs is the wrong length for indexing by a logical matrix"。在此处似乎也不适用replace函数,它返回相同的错误消息。有什么想法吗?
4个回答

6

由于结果的维度不同(是一个三维数组而不是一个二维矩阵),因此您不能仅仅逐个替换元素。

您可以使用 apply:通常用于对矩阵的每列或每行应用函数,但我们也可以使用它来将函数应用于每个元素。

apply( 
  test, 
  1:2, 
  function(u) list(c(0,0,0), c(0,0,1), c(0,1,0), c(1,0,1))[[u+1]] 
)

1
+1 表示“apply”可以同时在不同的边距上使用,这对我来说是个好消息! - thelatemail
我也认为这很优雅,但是因为我知道apply是n维的,所以我对从向量方面进行流畅选择印象深刻。 - IRTFM

3
你可以这样做:
Z <- matrix(c(0, 1, 0, 0,
              0, 0, 1, 0,
              0, 0, 0, 1), nrow = 3)

sapply(test, function(i)Z[,i+1])
#      X1 X2 X3 X4 X5 X6 X7 X8 X9
# [1,]  0  1  0  0  0  0  1  0  0
# [2,]  0  0  1  0  0  0  0  0  0
# [3,]  1  0  0  0  1  1  0  1  1
# ...
# [28,]  0  1  1  0  0  0  1  0  0
# [29,]  0  0  0  0  0  0  0  0  0
# [30,]  1  0  0  0  1  1  0  0  1

3
您可以使用switch来扩展:
matrix( sapply( c(1+data.matrix(test)), 
                    switch, c(0,0,0), c(0,0,1), c(0,1,0), c(1,0,1)) , 
        nrow=nrow(test)*3 ) 
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
 [1,]    1    0    0    0    1    1    0    1    1
 [2,]    0    1    0    0    0    0    1    0    0
 [3,]    1    0    0    1    1    1    0    1    1
 [4,]    0    0    0    0    1    1    0    0    1
 [5,]    0    0    0    0    0    0    1    0    0
 [6,]    0    1    0    1    1    1    0    0    1
 snipped remaining rows


str( matrix( sapply( c(1+data.matrix(test)), 
                    switch, c(0,0,0), c(0,0,1), c(0,1,0), c(1,0,1)) , 
        nrow=nrow(test)*3 ) )
  num [1:30, 1:9] 1 0 1 0 0 0 1 0 1 0 ...

2

您的输入是一个数据框,因此双重sapply方法也可以使用:

f <- function(u) list(c(0,0,0), c(0,0,1), c(0,1,0), c(1,0,1))[[u+1]] 
#  borrowed from Vincent Zoonekynd's answer
sapply(test, sapply, f)

请注意,输出结果与OP所要求的完全相同(“结果矩阵的行数应为test的行数乘以3”)--这可能是优选三维数组(apply(1:2, ...)的结果)还是不优选,这取决于您想要实现什么目标。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接