r语言 - 当元素逗号分隔在另一行时合并行



你好,我有一个数据框架,如:

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遍历数据帧的每一行,以检查familyEventsgroups这三列中有哪些行与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

最新更新