[英]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.