将2D矩阵转换为3D数组

3

我有一个二维矩阵,想把它转换成三维数组,但是我的转换不正确。

我的目标是使它能够递归地工作,无论第三个维度有多少层。

以下是数据:

dfs <- (structure(c(-0.046, 0.676, -0.698, -0.047, 0.719, -0.646, -0.044, 
                             0.706, -0.667, 0.046, 0.769, -0.605, 0.047, 0.813, -0.551, 0.044, 
                             0.795, -0.578), dim = c(9L, 2L), dimnames = list(c("snatch:(Intercept)", 
                                                                                "snatch:weight", "snatch:age", "clean:(Intercept)", "clean:weight", 
                                                                                "clean:age", "total:(Intercept)", "total:weight", "total:age"
                             ), c("2.5 %", "97.5 %"))))

我所寻找的是类似于这样的东西。
$a
             X2.5%  X97.5%
(Intercept) -0.046   0.046
weight       0.676   0.769
age         -0.698  -0.605

$b
             X2.5%  X97.5%
(Intercept)  -0.047   0.047
weight        0.719   0.813
age          -0.646  -0.551

$c
             X2.5%  X97.5%
(Intercept)  -0.044   0.044
weight        0.706   0.795
age          -0.667  -0.578

我的脚本和我迄今为止所做的事情

rnames <- c("(Intercept)", "snatch", "age")
cnames <- colnames(dfs); cnames
lnames <- c("a", "b", "c"); lnames

array(
  data = matrix(data = type.convert(gsub("^[^:]+:\\s*", "", dfs), as.is=TRUE),
                nrow=nrow(dfs), ncol=ncol(dfs)),
  dim = c(nrow(dfs)/length(lnames), length(cnames), length(lnames)),
  dimnames = list(rows=rnames,
                  column=cnames,
                  level=lnames)) %>%
  apply(., 2, data.frame)
4个回答

2

你可以尝试使用split.data.frame,例如:

> split.data.frame(dfs, gsub(":.*", "", row.names(dfs)))
$clean
                   2.5 % 97.5 %
clean:(Intercept) -0.047  0.047
clean:weight       0.719  0.813
clean:age         -0.646 -0.551

$snatch
                    2.5 % 97.5 %
snatch:(Intercept) -0.046  0.046
snatch:weight       0.676  0.769
snatch:age         -0.698 -0.605

$total
                   2.5 % 97.5 %
total:(Intercept) -0.044  0.044
total:weight       0.706  0.795
total:age         -0.667 -0.578

是一个列表,不过。 - jay.sf

2
我们可以对2D矩阵(或数据框)进行转置,创建一个数组,其维度为列数、唯一前缀数和唯一后缀数(在此例中为(2, 3, 3)),然后使用aperm对数组进行转置。
aperm(array(t(dfs), c(2, 3, 3)), c(2, 1, 3)) 
# , , 1
# 
#        [,1]   [,2]
# [1,] -0.046  0.046
# [2,]  0.676  0.769
# [3,] -0.698 -0.605
# 
# , , 2
# 
#        [,1]   [,2]
# [1,] -0.047  0.047
# [2,]  0.719  0.813
# [3,] -0.646 -0.551
# 
# , , 3
# 
#        [,1]   [,2]
# [1,] -0.044  0.044
# [2,]  0.706  0.795
# [3,] -0.667 -0.578

为了避免使用硬编码,我们可以使用 dimnames 来获取维度的值以及结果数组的 dimnames

f <- \(x) {
  dn <- dimnames(x)
  dn2 <- c(asplit(apply(do.call(rbind, strsplit(dn[[1]], ':')), 2, unique), 2), dn[2])
  aperm(array(data=t(x), dim=c(ncol(x), length(dn2[[2]]), length(dn2[[1]])), dimnames=dn2[c(3, 2, 1)]), c(2, 1, 3)) 
}

f(dfs)
# , , snatch
# 
#              2.5 % 97.5 %
# (Intercept) -0.046  0.046
# weight       0.676  0.769
# age         -0.698 -0.605
# 
# , , clean
# 
#              2.5 % 97.5 %
# (Intercept) -0.047  0.047
# weight       0.719  0.813
# age         -0.646 -0.551
# 
# , , total
# 
#              2.5 % 97.5 %
# (Intercept) -0.044  0.044
# weight       0.706  0.795
# age         -0.667 -0.578

数据:

dfs <- structure(c(-0.046, 0.676, -0.698, -0.047, 0.719, -0.646, -0.044, 
0.706, -0.667, 0.046, 0.769, -0.605, 0.047, 0.813, -0.551, 0.044, 
0.795, -0.578), dim = c(9L, 2L), dimnames = list(c("snatch:(Intercept)", 
"snatch:weight", "snatch:age", "clean:(Intercept)", "clean:weight", 
"clean:age", "total:(Intercept)", "total:weight", "total:age"
), c("2.5 %", "97.5 %")))

1

我知道这个方法有点啰嗦,而且jay.sf和ThomasIsCoding的答案肯定更好,但是我想找到一种整洁的方式,并发现了abind()函数:

library(tidyverse)
library(abind)

dfs %>%
  as.data.frame() %>% 
  rownames_to_column("names") %>% 
  separate(names, into = c("group", "names"), extra = "drop") %>% 
  group_split(group) %>% 
  purrr::set_names(purrr::map_chr(., ~.$group[1])) %>% 
  map(~ select(.x, -group)) %>% 
  abind(., along = 3)

, , clean

     names       2.5 %    97.5 %  
[1,] "Intercept" "-0.047" " 0.047"
[2,] "weight"    " 0.719" " 0.813"
[3,] "age"       "-0.646" "-0.551"

, , snatch

     names       2.5 %    97.5 %  
[1,] "Intercept" "-0.046" " 0.046"
[2,] "weight"    " 0.676" " 0.769"
[3,] "age"       "-0.698" "-0.605"

, , total

     names       2.5 %    97.5 %  
[1,] "Intercept" "-0.044" " 0.044"
[2,] "weight"    " 0.706" " 0.795"
[3,] "age"       "-0.667" "-0.578"

1

这是您期望的代码:

a <- array(dfs, dim = c(3, 2, 3),
           dimnames = list(gsub(".*:", "", rownames(dfs))[1:3] , 
                           colnames(dfs)))

a <- setNames(lapply(1:3, function(i) a[,,i]), c("a", "b", "c"))

输出:

> a
$a
             2.5 % 97.5 %
(Intercept) -0.046 -0.047
weight       0.676  0.719
age         -0.698 -0.646

$b
             2.5 % 97.5 %
(Intercept) -0.044  0.046
weight       0.706  0.769
age         -0.667 -0.605

$c
             2.5 % 97.5 %
(Intercept)  0.047  0.044
weight       0.813  0.795
age         -0.551 -0.578

同时类 a 是列表


他们想要一个数组... - jay.sf
然后他/她需要删除第二行 a <- setNames(...) 并且更改 array() 中的 dimnames 如下:dimnames = list(..., ..., c("a,""b","c"),但是根据问题中所说的 我正在寻找的是这样的东西,我已经做到了。 - Reza Esmaeelzade

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