首页 > 解决方案 > 将 3D 数组转换为数据框

问题描述

我在 CSV 文件中有一个尺寸为 48 x 165 x 27(48 个源 ROI、165 个目标 ROI 和 27 个参与者)的 3D 数组。每个页面都是一个新参与者。

我想将其转换为一个数据框,其中每个参与者 (27) 都有一行,列标题是 48 个源和 165 个目标 ROI 的所有可能组合(即 [Source #1 x Target #1],[源 #1 x 目标 #2],[源 #1 x 目标 #3]...)。

我怎样才能在 R 中做到这一点?

在此处输入图像描述

标签: rmultidimensional-arraydata-manipulation

解决方案


编辑:更直接:

data.frame(aperm(ary, c(3,1,2)))
#       src1.tgt1 src2.tgt1 src3.tgt1 src1.tgt2 src2.tgt2 src3.tgt2 src1.tgt3 src2.tgt3 src3.tgt3
# part1         1         2         3         4         5         6         7         8         9
# part2        10        11        12        13        14        15        16        17        18
# part3        19        20        21        22        23        24        25        26        27
# part4        28        29        30        31        32        33        34        35        36

其余的继续展示我过度设计的第一次尝试:-)

(感谢@Onyambu!)


使用我的示例数据(如下):

library(dplyr)
library(tidyr)
apply(ary, 3, function(m) {
  as.data.frame.table(m) %>%
    transmute(Var = paste(Var1, Var2, sep = "_"), Freq) %>%
    spread(Var, Freq)
}) %>%
  bind_rows()
#   src1_tgt1 src1_tgt2 src1_tgt3 src2_tgt1 src2_tgt2 src2_tgt3 src3_tgt1 src3_tgt2 src3_tgt3
# 1         1         4         7         2         5         8         3         6         9
# 2        10        13        16        11        14        17        12        15        18
# 3        19        22        25        20        23        26        21        24        27
# 4        28        31        34        29        32        35        30        33        36

演练:

  • 我们可以将此 3d 数组的单个平面转换为 3 列表:

    as.data.frame.table(ary[,,1]) %>% head
    #   Var1 Var2 Freq
    # 1 src1 tgt1    1
    # 2 src2 tgt1    2
    # 3 src3 tgt1    3
    # 4 src1 tgt2    4
    # 5 src2 tgt2    5
    # 6 src3 tgt2    6
    
  • 鉴于此,我们想将Var1和组合Var2成一个变量(给出组合),然后从长转向宽:

    as.data.frame.table(ary[,,1]) %>%
      transmute(Var = paste(Var1, Var2, sep = "_"), Freq) %>%
      spread(Var, Freq)
    #   src1_tgt1 src1_tgt2 src1_tgt3 src2_tgt1 src2_tgt2 src2_tgt3 src3_tgt1 src3_tgt2 src3_tgt3
    # 1         1         4         7         2         5         8         3         6         9
    
  • 所以我们需要对每架飞机都这样做;鉴于这是一个array,我的第一个想法是

    apply(ary, MARGIN=3, function(m) {...})
    

    whereMARGIN=指示要迭代的数组。对于每个调用,m是一个 3x3 矩阵(在此示例中),是整个阵列的一个平面。

这可能可以简单地在基础 R 中完成,但我对基础 R 重塑的运气好坏参半;我觉得tidyr::spread直截了当。既然我加载了它,我就继续使用dplyr它,尽管这部分也很容易被排除在外。


样本数据:

ary <- array(1:36, dim=c(3,3,4))
dimnames(ary) <- list(paste0("src", 1:3), paste0("tgt", 1:3), paste0("part", 1:4))
ary
# , , part1
#      tgt1 tgt2 tgt3
# src1    1    4    7
# src2    2    5    8
# src3    3    6    9
# , , part2
#      tgt1 tgt2 tgt3
# src1   10   13   16
# src2   11   14   17
# src3   12   15   18
# , , part3
#      tgt1 tgt2 tgt3
# src1   19   22   25
# src2   20   23   26
# src3   21   24   27
# , , part4
#      tgt1 tgt2 tgt3
# src1   28   31   34
# src2   29   32   35
# src3   30   33   36

推荐阅读