你好,我有一个数据框架,如:
species family Events groups
1 SP1 A 10,22 G1
2 SP1 B 7 G2
3 SP1 C,D 4,5,6,1,3 G3,G4,G5,G6
4 SP2 A 22,10 G1
5 SP2 D,C 6,5,4,3,1 G4,G6,G5,G3
6 SP3 C 4,5,3,6,1 G3,G6,G5
7 SP3 E 7 G2
8 SP3 A 10 G1
9 SP4 C 7,22 G12
和我想简单地合并行,每个列中至少有一个重复的元素(species
除外)。
例如我将合并行:
species family Events groups
SP1 A 10,22 G1
species family Events groups
SP2 A 22,10 G1
species family Events groups
SP3 A 10 G1
到
species family Events groups
SP1,SP2,SP3 A 10,22 G1
因此,如果我对每一行执行相同的操作,我应该得到预期的输出:
species family Events groups
SP1,SP2,SP3 A 10,22 G1
SP1,SP3 B,E 7 G2
SP1,SP2,SP3 C,D 1,3,4,5,6 G3,G4,G6,G5
SP4 C 7,22 G12
请注意,SP4没有与任何行合并,因为它的组没有出现在任何其他行中。
有人有什么主意吗?非常感谢您的帮助和时间
如果可以的话,这里是数据框架:
structure(list(species = structure(c(1L, 1L, 1L, 2L, 2L, 3L,
3L, 3L, 4L), .Label = c("SP1", "SP2", "SP3", "SP4"), class = "factor"),
family = structure(c(1L, 2L, 4L, 1L, 5L, 3L, 6L, 1L, 3L), .Label = c("A",
"B", "C", "C,D", "D,C", "E"), class = "factor"), Events = structure(c(2L,
7L, 5L, 3L, 6L, 4L, 7L, 1L, 8L), .Label = c("10", "10,22",
"22,10", "4,5,3,6,1", "4,5,6,1,3", "6,5,4,3,1", "7", "7,22"
), class = "factor"), groups = structure(c(1L, 3L, 4L, 1L,
6L, 5L, 3L, 1L, 2L), .Label = c("G1", "G12", "G2", "G3,G4,G5,G6",
"G3,G6,G5", "G4,G6,G5,G3"), class = "factor")), class = "data.frame", row.names = c(NA,
-9L))
我能做的和尝试的:
到目前为止,我只知道如何合并行与精确重复的值使用类似的东西在dplyr:
desired_df <- df %>%
group_by_at(vars(-species)) %>%
summarize(species = toString(species)) %>%
ungroup() %>%
select(names(df))
,但这里我们没有精确的重复值,相反,我正在寻找可以出现在另一行的comma
之间。
这是一个完整的解决方案(调用输入数据帧dat
)。
请注意,此解决方案与您给出的期望输出不相同。这是因为您声明的规则是"合并"每列至少有一个重复元素的行,但"物种"除外。根据该规则,第2行和第7行不应该合并,因为它们没有共同的family
。
首先,将我们要测试重叠值的三个列转换为列表列。现在这些列中的每个元素都是一个列表。我还将Events
列强制为数字,以便它能够正确排序。
library(tidyverse)
dat <- dat %>%
mutate(across(c(family, Events, groups), ~ strsplit(as.character(.), split = ','))) %>%
mutate(Events = map(Events, as.numeric))
接下来,定义一个函数来折叠数据帧的每一行。该函数接受参数i
,这是一个行索引。在函数中,我们做两件事:
- 首先,我们使用
pmap_lgl
遍历数据帧的每一行,以检查family
、Events
和groups
这三列中有哪些行与i
行至少有一个共享值,因此应该折叠。例如,如果i==1
,这将返回TRUE
的第1、4和8行。 - 接下来,我们只对返回
TRUE
的行过滤dat
,并对这些行的所有列应用一个函数。该函数将这些行中的所有列折叠为逗号分隔的排序唯一值字符串。
collapse_rows <- function(i) {
rows_collapse <- pmap_lgl(dat, function(family, Events, groups, ...)
any(dat$family[[i]] %in% family) & any(dat$Events[[i]] %in% Events) & any(dat$groups[[i]] %in% groups))
dat %>%
filter(rows_collapse) %>%
mutate(across(everything(), ~ paste(sort(unique(unlist(.))), collapse = ',')))
}
最后,我们将此函数应用于每个行索引。我们最终得到了重复的行,例如初始输出的第1、4和8行是相同的。我们使用distinct
删除所有这些重复项。
dat_collapse <- map_dfr(1:nrow(dat), collapse_rows) %>% distinct
最终输出:
species family Events groups
1 SP1,SP2,SP3 A 10,22 G1
2 SP1 B 7 G2
3 SP1,SP2,SP3 C,D 1,3,4,5,6 G3,G4,G5,G6
4 SP3 E 7 G2
5 SP4 C 7,22 G12