首页 > 解决方案 > 数据集中所有可能的组合与在 R 中按顺序排列的嵌套组

问题描述

我早些时候发布了这个问题,但经过一些评论后,我意识到需要更好地解释dfand result。此外,我意识到可以使用简化的数据结构来实现我的目标。

我需要找到特定序列中的所有值组合。

在示例df中,您可以看到嵌套的分组结构,其中GROUP嵌套了SAMPLESITESAMPLE我的实际数据集在 30中有 ~1000 SITE。请注意,每个GROUP都按顺序(1 到 3),并且该顺序需要保留在最终结果中,因为这是未来分析的关键部分。换句话说,不需要将GROUP2 或 3放在 1 之前的组合。GROUP

每个中的、和列GROUP中有 2 或 3 个文本或数值。比如F1有3组,每组有2种可能性:1有4个和unk_palmer_trib;2有6.1和5.2;'GROUP' 3 有 10.1 和 6.1。您可以看到B2 也有三个组,其中1 和 3 有两种可能性,而2 有三种可能性。ASSIGN_1ASSIGN_2ASSIGN_3GROUPGROUPSAMPLEGROUPGROUP

所以……我需要找到ASSIGN列中值的所有可能组合,同时保留GROUP. 请注意,OPTION中的列是来自 中的列result的值的各种组合,您会注意到这些组合保留了顺序(即 1 到 3)。另请注意,包含数据的列数(即没有“NAs”)对应于保留序列的列的所有可能组合。F1 有 3 组,每组有 2 种可能性,因此有 8 种可能的结果(即 2 x 2 x 2;见第 1 至第 8 列)。ASSIGNdfGROUPOPTIONresultASSIGNGROUPSAMPLEOPTIONSAMPLEB2 有 3 组(2 组有两种可能性,1 组有三种可能性),因此有 12 种可能的结果(即 2 x 3 x 2;见OPTION第 1 至第 12 列)。

为了真正推动这一点,让我们看看SAMPLEF1dfresult以说明如何构建这些组合。OPTION_1因为 F1 只是ASSIGN_1来自 的列dfOPTION_2是来自ASSIGN_1(即,GROUP_1 = 4)的第 1 行,然后是来自 ASSIGN_2 的第 2 行和第 3 行(即,GROUP_2 = 5.2 和 GROUP_3 = 6.1)。'OPTION_3' 是来自ASSIGN_1(即,GROUP_1 = 4)的第 1 行,来自ASSIGN_2(即,GROUP_2 = 5.2)的第 2 行和来自ASSIGN_1(即,GROUP_3 = 10.1)的第 3 行。在恶心处重复……

在我的实际数据集中,其中一些GROUP最多可以有 5ASSIGN列……所以可能的组合数量对于某些SAMPLE.

我曾尝试使用expand.grid()within ave(),但无法使代码正常工作。我对所有解决方案持开放态度,但更喜欢base package解决方案,因为我想避免加载包。我还怀疑df可能需要以某种方式重组……只要GROUP序列保留在最终产品中,这完全没问题。

让我知道是否需要澄清。

在此先感谢您的帮助。

df <- read.table(text = "SITE   SAMPLE  GROUP   ASSIGN_1    ASSIGN_2    ASSIGN_3
A1  F1  1   4   unk_palmer_trib NA
A1  F1  2   6.1 5.2 NA
A1  F1  3   10.1    6.1 NA
M15 B2  1   6.2 6.4 NA
M15 B2  2   10.1    6.1 5.2
M15 B2  3   10.1    6.1 NA
", header = TRUE)

result <- read.table(text = "SITE   SAMPLE  GROUP   OPTION_1    OPTION_2    OPTION_3    OPTION_4    OPTION_5    OPTION_6    OPTION_7    OPTION_8    OPTION_9    OPTION_10   OPTION_11   OPTION_12
A1  F1  1   4   4   4   4   unk_palmer_trib unk_palmer_trib unk_palmer_trib unk_palmer_trib NA  NA  NA  NA
A1  F1  2   6.1 5.2 5.2 6.1 6.1 5.2 5.2 6.1 NA  NA  NA  NA
A1  F1  3   10.1    6.1 10.1    6.1 10.1    6.1 10.1    6.1 NA  NA  NA  NA
M15 B2  1   6.2 6.2 6.2 6.2 6.2 6.2 6.4 6.4 6.4 6.4 6.4 6.4
M15 B2  2   10.1    6.1 10.1    6.1 5.2 5.2 10.1    6.1 10.1    6.1 5.2 5.2
M15 B2  3   10.1    6.1 6.1 10.1    10.1    6.1 10.1    6.1 6.1 10.1    10.1    6.1
", header = TRUE)

标签: r

解决方案


这是一个刺:-)

func <- function(x, keep = integer(0)) {
  if (length(keep)) {
    saved <- x[,keep,drop=FALSE]
    x <- x[,-keep]
  } else {
    saved <- x[,0] # empty column
  }
  out <- t(do.call(expand.grid, asplit(t(x), 2)))
  out <- as.data.frame(out[, colSums(is.na(out)) == 0])
  colnames(out) <- paste0("OPTION_", seq_along(out))
  cbind(saved, out)
}

keep=参数是需要在组合中保留而不是扩展的字段的整数向量。

示范:

LOF <- Filter(length, by(df, df[,c("SITE","SAMPLE")], FUN = func, keep = 1:3))
allnames <- unique(unlist(lapply(LOF, colnames)))
LOF <- lapply(LOF, function(z) { z[setdiff(allnames, colnames(z))] <- NA; z; })
do.call(rbind, LOF)
#   SITE SAMPLE GROUP OPTION_1        OPTION_2 OPTION_3        OPTION_4 OPTION_5        OPTION_6 OPTION_7        OPTION_8 OPTION_9 OPTION_10 OPTION_11 OPTION_12
# 4  M15     B2     1      6.2             6.4      6.2             6.4      6.2             6.4      6.2             6.4      6.2       6.4       6.2       6.4
# 5  M15     B2     2     10.1            10.1      6.1             6.1      5.2             5.2     10.1            10.1      6.1       6.1       5.2       5.2
# 6  M15     B2     3     10.1            10.1     10.1            10.1     10.1            10.1      6.1             6.1      6.1       6.1       6.1       6.1
# 1   A1     F1     1      4.0 unk_palmer_trib      4.0 unk_palmer_trib      4.0 unk_palmer_trib      4.0 unk_palmer_trib     <NA>      <NA>      <NA>      <NA>
# 2   A1     F1     2      6.1             6.1      5.2             5.2      6.1             6.1      5.2             5.2     <NA>      <NA>      <NA>      <NA>
# 3   A1     F1     3     10.1            10.1     10.1            10.1      6.1             6.1      6.1             6.1     <NA>      <NA>      <NA>      <NA>

如果您已经在使用data.table,那么这可以简化为第一个加上第二个或第三个:

LOF <- Filter(length, by(df, df[,c("SITE","SAMPLE")], FUN = func, keep = 1:3))
data.table::rbindlist(LOF, fill = TRUE, use.names = TRUE)
dplyr::bind_rows(LOF)

推荐阅读