如何在一个大型数据框中,基于两列完全相同的值进行去重,并将剩余的列合并成一行?

编程语言 2026-07-09

示例数据:

ID<-c("A","A","A","A","A","A","B","B","B")
HFAdmission<-c("2020-01-01", "2020-02-01", "2020-03-01", NA, NA, NA, "2020-06-01", "2020-07-01", NA)
link_type<-c("Linked", "HF only", "HF only", "HES only", "HES only", "HES only", "Linked", "HF only", "HES only")
ADMIDATE<-c(NA,NA,NA,"2020-03-01","2020-04-01","2020-05-01",NA,NA, "2020-07-01")
newdate<-c(NA, "2020-02-01", "2020-03-01", "2020-03-01","2020-04-01","2020-05-01", NA, "2020-07-01", "2020-07-01")
df<-data.frame(ID, HFAdmission,link_type,ADMIDATE,newdate)

as.Date(df$HFAdmission)
as.Date(df$ADMIDATE)
as.Date(df$newdate)

df应该如下所示:

  ID HFAdmission link_type   ADMIDATE    newdate
1  A  2020-01-01    Linked       <NA>       <NA>
2  A  2020-02-01   HF only       <NA> 2020-02-01
3  A  2020-03-01   HF only       <NA> 2020-03-01
4  A        <NA>  HES only 2020-03-01 2020-03-01
5  A        <NA>  HES only 2020-04-01 2020-04-01
6  A        <NA>  HES only 2020-05-01 2020-05-01
7  B  2020-06-01    Linked       <NA>       <NA>
8  B  2020-07-01   HF only       <NA> 2020-07-01
9  B        <NA>  HES only 2020-07-01 2020-07-01

我希望基于两列(ID和 newdate)进行去重。

例如,设ID为 A,在第3 行和第4 行的newdate存在重复。

新创建的行在可能的情况下不会包含NA,因为来自第3 行的HFAdmission日期会被保留,而不是第4 行HDAdmission中的NA;同样来自第4 行的ADMIDATE日期将被保留,而不是第3 行的ADMIDATE中的NA。

当某列中存在两个非NA值时(例如link_type),该列应保留重复中的第一个非缺失值。

同样的情况也适用于第8 行和第9 行的重复。

去重并合并后的期望结果(第4 行和第9 行)如下:

  ID HFAdmission link_type   ADMIDATE    newdate
1  A  2020-01-01    Linked       <NA>       <NA>
2  A  2020-02-01   HF only       <NA> 2020-02-01
3  A  2020-03-01   HF only 2020-03-01 2020-03-01
4  A        <NA>  HES only 2020-04-01 2020-04-01
5  A        <NA>  HES only 2020-05-01 2020-05-01
6  B  2020-06-01    Linked       <NA>       <NA>
7  B  2020-07-01   HF only 2020-07-01 2020-07-01

我的数据集很大(一个5GB的 CSV文件),因此我一直在尝试使用基础R 函数,包括duplicated和 aggregate,但都没有成功。

解决方案

由于问题强调性能,我认为这里应避免直接的split-apply-combine方法(也就是把数据框按唯一的 IDnewdate 的组合拆分成组,在每个组中取每列的第一个非缺失值,然后再拼接)。若存在大量这样的分组,下面这种基于连接的解法在速度上会更快,同时内存占用也应保持在一个可接受的范围内。

First, create a new data frame df_new with the deduplicated value pairs of ID and newdate.

Then, for each of the other columns, add a new column to df_new containing the first non-missing value at each value pair, by:

  • 删除 NAs
  • IDnewdate 上进行连接,只选择首次遇到的匹配项。
library(data.table)

setDT(df)
unique_cols <- c("ID", "newdate")
df_new <- df[, unique(.SD), .SDcols=unique_cols]

for (col in setdiff(names(df), unique_cols)) {
  env <- list(v=col)
  x <- df[!is.na(v), .SD, .SDcols=c(unique_cols, col), env=env]
  df_new[[col]] <- x[df_new, on=unique_cols, mult="first", v, env=env]
}
setDF(df_new)

df_new
#>   ID    newdate HFAdmission link_type   ADMIDATE
#> 1  A       <NA>  2020-01-01    Linked       <NA>
#> 2  A 2020-02-01  2020-02-01   HF only       <NA>
#> 3  A 2020-03-01  2020-03-01   HF only 2020-03-01
#> 4  A 2020-04-01        <NA>  HES only 2020-04-01
#> 5  A 2020-05-01        <NA>  HES only 2020-05-01
#> 6  B       <NA>  2020-06-01    Linked       <NA>
#> 7  B 2020-07-01  2020-07-01   HF only 2020-07-01
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章