【问题标题】:Is there an inner_join equivalent for multidimensional arrays in R?R中的多维数组是否有等效的inner_join?
【发布时间】:2020-04-01 14:35:05
【问题描述】:

对于 3d 数组是否有某种等价的 inner_join,可以将 2d 结构连接到 3d 结构吗?

让我们看看这是否有意义:

我有一个 3d 整数数组(微生物组计数数据)。

  • 维度 1:复制 1:100
  • 维度 2:样本
  • 维度 3:分类群

我有一个二维元数据表。

  • 维度 1:样本
  • 维度 2:元数据类型(稀释、采样日期等)

二维元数据表(样本名称)中有一列与数组中第二维的标签匹配。

我能否以某种方式加入这两者,以便保留数组结构并为每个样本添加元数据?

我是否必须将阵列熔化/堆叠成超长的二维表?

感谢您的帮助!

-编辑

假设我使用以下代码生成了一个数组 a 和“a”表“b”:

a <- array(1:10,c(2,4,3))
b <- data.frame("thing" = c("stuff", "foo", "dodad"), "data" = c(10,20,30), "match" = c("first","second","third"))
dimnames(a) <- list(c("A", "B"), c("one", "two", "three", "four"), c("first", "second", "third"))

如您所见,我在表“b”中有一个“匹配”列,我想将其加入/匹配到维度名称 a[[3]]。

如果我们看一下“a”和“b”

> a
, , first

  one two three four
A   1   3     5    7
B   2   4     6    8

, , second

  one two three four
A   9   1     3    5
B  10   2     4    6

, , third

  one two three four
A   7   9     1    3
B   8  10     2    4

> b
  thing data  match
1 stuff   10  first
2   foo   20 second
3 dodad   30  third

例如,我想要数组

, , third

      one two three four
    A   7   9     1    3
    B   8  10     2    4

让元素“dodad”和“30”与标签“thing”和“data”相关联。

对于真实数据集,我希望使用“患者姓名”而不是“事物”和“稀释”而不是“数据”,并使用这些元素作为从数组中提取切片以运行统计的手段分析。

【问题讨论】:

  • 我不知道有一个常见的多维类比 join/merge。您能否提供 small 样本数据(可能是 4x3x2 与 4x3 连接)和预期输出?我建议您使用arraymatrix 以编程方式构建数据,或者使用dput 转储数据。谢谢。
  • 谢谢,我进行了编辑。见上文
  • 好的开始,预期的输出呢?
  • 谢谢,见上文

标签: r arrays inner-join metadata


【解决方案1】:

你没有显示你想要的输出,所以我猜。

如果您以a(带有暗淡AxBxC)和b(暗淡DxE)开始,那么您应该得到一个带有暗淡AxBxD的数组。

a[,,b[,"match"]]
# , , first
#   one two three four
# A   1   3     5    7
# B   2   4     6    8
# , , second
#   one two three four
# A   9   1     3    5
# B  10   2     4    6
# , , third
#   one two three four
# A   7   9     1    3
# B   8  10     2    4

就组合输出而言,您提供的数据不可能发生:矩阵a 具有所有数据必须是同一类的约束,但您的b 是具有不同类的框架。因此,如果您需要在 a 中保留数字,在 b 中保留字符串或因子,那么您不能只将一个合并到另一个。

你有一些选择:

  1. 如果您的第二帧真的可以是矩阵,那么我们可以这样做。

    ### a naive conversion, your case may vary with real data
    bnum <- sapply(b, as.integer)
    dim(bnum) <- c(dim(bnum), 1)
    dimnames(bnum) <- list(rownames(b), colnames(b), NULL)
    bnum
    # , , 1
    #   thing data match
    # 1     3   10     1
    # 2     2   20     2
    # 3     1   30     3
    
    ### the solution
    abind::abind(
      apply(bnum[,-3,1], 2:1, rep, times = dim(a)[1]),
      a[,,bnum[,"match",1]],
      along = 2
    )
    # , , first
    #   thing data one two three four
    # A     3   10   1   3     5    7
    # B     3   10   2   4     6    8
    # , , second
    #   thing data one two three four
    # A     2   20   9   1     3    5
    # B     2   20  10   2     4    6
    # , , third
    #   thing data one two three four
    # A     1   30   7   9     1    3
    # B     1   30   8  10     2    4
    
  2. 如果您需要保持 b 原样,那么您无法制作 3-d 数组。一种选择是以列表列的方式嵌套a 的每一层。

    out <- within(b, { mtx = lapply(match, function(m) a[,,m]) })
    out
    #   thing data  match                     mtx
    # 1 stuff   10  first  1, 2, 3, 4, 5, 6, 7, 8
    # 2   foo   20 second 9, 10, 1, 2, 3, 4, 5, 6
    # 3 dodad   30  third 7, 8, 9, 10, 1, 2, 3, 4
    

    虽然看起来它丢失了a 的 z 层布局,但这只是控制台上的不良表现。还是不错的:

    out$mtx[[1]]
    #   one two three four
    # A   1   3     5    7
    # B   2   4     6    8
    

    如果您有兴趣,也可以使用dplyrdata.table 来完成。

    library(dplyr)
    out <- b %>%
      mutate(mtx = lapply(match, function(m) a[,,m]))
    # option to use purrr::map instead of lapply
    
    library(data.table)
    out <- as.data.table(b)[, mtx := lapply(match, function(m) a[,,m]) ]
    

【讨论】:

  • 感谢您的快速回复!第二个解决方案做到了!
猜你喜欢
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 2019-12-31
  • 2015-06-01
  • 1970-01-01
  • 2015-05-10
  • 1970-01-01
  • 2019-08-19
相关资源
最近更新 更多