将晦涩的表格转换为矩阵

3

我有一个表格,长这样:

Row Col Value
1   1   31
1   2   56
1   8   13
2   1   83
2   2   51
2   9   16
3   2   53

我需要将这个表格转换为矩阵(Row列代表行,Col列代表列)。输出结果应该如下:
   1  2  3  4  5  6  7  8  9 
1 31 56 NA NA NA NA NA 13 NA
2 81 51 NA NA NA NA NA NA 16
3 NA 53 NA NA NA NA NA NA NA

我相信有一种快速的方法可以实现我的想法,我的解决方案将循环每个行/列组合并使用cbind组合所有内容。

可重复示例:

require(data.table)
myTable <- data.table(
           Row = c(1,1,1,2,2,2,3),
           Col = c(1,2,8,1,2,9,1),
           Value = c(31,56,13,83,51,16,53))

您的数据不一致;在您的“我有一个看起来像这样的表格”中,最终的列值为2,在您的“可重现示例”中为1。 - bgoldst
4个回答

4

简单明了:

dat <- data.frame(
         Row = c(1,1,1,2,2,2,3),
       Col = c(1,2,8,1,2,9,1),
       Value = c(31,56,13,83,51,16,53))
m = matrix(NA, nrow = max(dat$Row), ncol = max(dat$Col))
m[cbind(dat$Row, dat$Col)] = dat$Value
m

这不是预期的结果。 - Colonel Beauvel
这对于大小为(1000x1000)的表格需要多长时间?解决方案简单、清晰易懂,但需要一些时间。 - SimBea
@SimBea,您的意思是结果应该是1000 X 1000吗? - A5C1D2H2I1M1N2O1R2T1
@SimBea 如果你想要在整个矩阵中都有“NA”,那么这个答案应该是最快的方法。对于某些代数运算来说,稀疏矩阵更好,并且可能占用更少的空间。 - Frank

4
稀疏矩阵。您可能需要一种稀疏矩阵。
require(Matrix) # doesn't require installation
mySmat <- with(myTable,sparseMatrix(Row,Col,x=Value))

这提供了

3 x 9 sparse Matrix of class "dgCMatrix"

[1,] 31 56 . . . . . 13  .
[2,] 83 51 . . . . .  . 16
[3,] 53  . . . . . .  .  .

矩阵。如果您确实需要具有NAmatrix类对象,则有以下方法:

myMat <- as.matrix(mySmat)
myMat[myMat==0] <- NA

这提供了

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]   31   56   NA   NA   NA   NA   NA   13   NA
[2,]   83   51   NA   NA   NA   NA   NA   NA   16
[3,]   53   NA   NA   NA   NA   NA   NA   NA   NA

效率考虑。 为了写更短的代码:

myMat <- with(myTable,as.matrix(sparseMatrix(Row,Col,x=Value)))
myMat[myMat==0] <- NA

为了更快的速度(但比创建稀疏矩阵慢),可以像 @jimmyb 和 @bgoldst 一样,将其初始化为NA并填充:

myMat <- with(myTable,matrix(,max(Row),max(Col)))
myMat[cbind(myTable$Row,myTable$Col)] <- myTable$Value

只有在您坚持使用 NA 而不是零时,才需要使用此解决方法。稀疏矩阵几乎肯定是您应该使用的。创建和处理它应该更快,并且存储它应该更少占用内存。


1
很好,你甚至可以使用as.matrix来进行“清晰可视化”的包装! - Colonel Beauvel
@ColonelBeauvel 你的意思是在一行里吗?不幸的是,我无法想出一种方式将替换为“NA”的内容放入其中。似乎稀疏矩阵的as.matrix应该有一个选项可以将零读作NA,但我找不到这样的选项。无论如何,我会写两行代码 :) - Frank

2

我认为最简洁和高效的方法是使用NA预分配矩阵,然后通过手动计算从RowCol得到线性索引来分配向量切片:

df <- data.frame(Row=c(1,1,1,2,2,2,3), Col=c(1,2,8,1,2,9,2), Value=c(31,56,13,83,51,16,53) );
m <- matrix(NA,max(df$Row),max(df$Col));
m[(df$Col-1)*nrow(m)+df$Row] <- df$Value;
m;
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,]   31   56   NA   NA   NA   NA   NA   13   NA
## [2,]   83   51   NA   NA   NA   NA   NA   NA   16
## [3,]   NA   53   NA   NA   NA   NA   NA   NA   NA

1
顺便说一句,在我的经验中,线性和矩阵索引在这种赋值情况下的速度大致相同。但无论如何,我所知道的没有比这个答案更快的了。 - Frank

1
在基础R中,xtabs非常适合这种情况,如果您可以接受在NA处使用"0"。这是基本方法:
xtabs(Value ~ Row + Col, myTable)
#    Col
# Row  1  2  8  9
#   1 31 56 13  0
#   2 83 51  0 16
#   3 53  0  0  0

然而,这并不能填补所有因素水平不可用的空缺。你可以分别完成此操作,或像这样实时完成:
xtabs(Value ~ factor(Row, sequence(max(Row))) + 
      factor(Col, sequence(max(Col))), myTable)
#                                factor(Col, sequence(max(Col)))
# factor(Row, sequence(max(Row)))  1  2  3  4  5  6  7  8  9
#                               1 31 56  0  0  0  0  0 13  0
#                               2 83 51  0  0  0  0  0  0 16
#                               3 53  0  0  0  0  0  0  0  0

扩展开来,这意味着如果“Row”和“Col”值是因子,dcast.data.table 应该也能够工作:

dcast.data.table(myTable, Row ~ Col, value.var = "Value", drop = FALSE)

但是出于某些原因,在我的测试中它并没有起作用。我不得不使用library(reshape2); dcast(myTable, Row ~ Col, value.var = "Value", drop = FALSE)来使它工作,因此无法利用"data.table"的速度。


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