[英]All possible combinations in data set with nested groups that are ordered sequencially in R
我早些时候发布了这个问题,但经过一些评论后,我意识到需要对df
和result
进行更好的解释。 此外,我意识到可以使用简化的数据结构来实现我的目标。
我需要找到特定序列中的所有值组合。
在示例df
中,您可以看到嵌套的分组结构,其中GROUP
嵌套在SAMPLE
和SITE
中。 我的实际数据集在 30 个SITE
中有 ~1000 SAMPLE
。 请注意,每个GROUP
都是按顺序排列的(1 到 3),并且该顺序需要保留在最终结果中,因为这是未来分析的关键部分。 换句话说,不需要将GROUP
2 或 3 放在GROUP
1 之前的组合。
每个GROUP
在ASSIGN_1
、 ASSIGN_2
和ASSIGN_3
列中有 2 或 3 个文本或数值。 比如F1有3组,每组有2种可能性: GROUP
1有4个和unk_palmer_trib; 第 2 GROUP
有 6.1 和 5.2; 'GROUP' 3 有 10.1 和 6.1。 您可以看到SAMPLE
B2 也有三个GROUP
,第 1 组和第 3 组有两种可能性,第 2 GROUP
有三种可能性。
所以……我需要找到ASSIGN
列中所有可能的值组合,同时保留GROUP
的序列。 请注意, result
中的OPTION
列是df
中ASSIGN
列的值的各种组合,您会注意到这些组合保留了GROUP
序列(即 1 到 3)。 另请注意, result
中包含数据的OPTION
列数(即没有“NAs”)对应于保留GROUP
序列的ASSIGN
列的所有可能组合。 SAMPLE
F1 有 3 组,每组有 2 种可能性,因此有 8 种可能的结果(即 2 x 2 x 2;参见OPTION
列 1 至 8)。 SAMPLE
B2 有 3 组(2 组有两种可能性,1 组有三种可能性),因此有 12 种可能的结果(即 2 x 3 x 2;参见OPTION
列 1 至 12)。
为了真正推动这一点,让我们看看df
中的SAMPLE
F1 和result
,以说明如何构建这些组合。 F1 的OPTION_1
只是df
的ASSIGN_1
列。 OPTION_2
是ASSIGN_1
的第 1 行(即 GROUP_1 = 4),然后是 ASSIGN_2 的第 2 行和第 3 行(即 GROUP_2 = 5.2 和 GROUP_3 = 6.1)。 'OPTION_3' 是ASSIGN_1
的第 1 行(即 GROUP_1 = 4)、 ASSIGN_2
的第 2 行(即 GROUP_2 = 5.2)和ASSIGN_1
的第 3 行(即 GROUP_3 = 10.1)。 在恶心处重复……
在我的实际数据集中,某些GROUP
最多可以有 5 个ASSIGN
列……因此对于某些SAMPLE
可能的组合数量可能很大。
我尝试在ave()
中使用expand.grid()
) ,但无法使代码正常工作。 我对所有解决方案持开放态度,但更喜欢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)
这是一个刺:-)
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=
参数是需要在组合中保留而不是扩展的字段的 integer 向量。
示范:
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.