Data.table 有重复的条目,但所有列都不匹配、为空或有更正

Data.table with duplicate entries but all columns dont match, are empty, or have correctiona

我有一个包含重复条目的数据集。他们很可能是由于数据错误。条目错误后,将用另一个条目更正。人们将如何使用这些数据。举个例子:

dt1 <- data.table(
    id = c('a','','a','b','','b','c','','c'), 
    v1 =c('a','a','a','b','b','','c','','c'), 
    v2 =c('a','a','a','b','','b','','','c'), 
    v3 =c('a','a','a','','b','','','c',''), 
    v4 =c('','a','','b','','','c','','c'), 
    v5 =c('a','','a','','','b','','','c'), 
    v6 =c('','a','','','b','b','c','c','c')
    )

我想要什么:

dt1 <- data.table(
    id =c('a','b','c'),
    v1 =c('a','b','c'),
    v2 =c('a','b','c'),
    v3 =c('a','b','c'),
    v4 =c('a','b','c'),
    v5 =c('a','b','c'),
    v6 =c('a','b','c'),
    )

上面的例子,认为id代表id变量,v1-v6填充的是随机信息

这是一个使用 tidyverse 的解决方案。这个想法是首先用 NA 替换 "",使用 fill 来估算 id 列,group_by id,以及 summarize 每列保存信息。

不清楚你的“随机信息”是什么样子的,你想如何总结这些信息。在这里,我假设您想在每个 id 和每一列中保留第一个非 NA 值。这就是 ~first(.x[!is.na(.x)])) 正在努力实现的目标。如果您有其他方法来汇总数据,请在此位置提供您的功能。

library(tidyverse)

dt1[dt1 == ""] <- NA

dt1_2 <- dt1 %>%
  fill(id, .direction = "downup") %>%
  group_by(id) %>%
  summarize(across(.fns = ~first(.x[!is.na(.x)]))) %>%
  ungroup()

dt1_2
# # A tibble: 3 x 7
#   id    v1    v2    v3    v4    v5    v6   
#   <chr> <chr> <chr> <chr> <chr> <chr> <chr>
# 1 a     a     a     a     a     a     a    
# 2 b     b     b     b     b     b     b    
# 3 c     c     c     c     c     c     c

更新

下面的代码展示了如何使用 tow across 将不同的函数应用于不同的列组。

dt1_2 <- dt1 %>%
  fill(id, .direction = "downup") %>%
  group_by(id) %>%
  summarize(across(v1:v4, .fns = ~first(.x[!is.na(.x)])),
            across(v5:v6, .fns = ~last(.x[!is.na(.x)]))) %>%
  ungroup()

更新2

这是一个更新的解决方案,它处理没有任何重复项包含非 NA 值的情况。

dt2 <- data.table(
  id = c('a','','a','b','','b','c','','c'), 
  v1 =c('a','a','a','b','b','','c','','c'), 
  v2 =c('a','a','a','b','','b','','',''), 
  v3 =c('a','a','a','','b','','','c',''), 
  v4 =c('','a','','b','','','c','','c'), 
  v5 =c('a','','a','','','b','','','c'), 
  v6 =c('','a','','','b','b','c','c','c')
)

dt2[dt2 == ""] <- NA

fill_fun <- function(x, fun){
  if (all(is.na(x))){
    result <- NA
  } else {
    result <- fun(x[!is.na(x)])
  }
  return(result)
}


dt2_2 <- dt2 %>%
  fill(id, .direction = "downup") %>%
  group_by(id) %>%
  summarize(across(v1:v4, .fns = ~fill_fun(.x, fun = first)),
            across(v5:v6, .fns = ~fill_fun(.x, fun = last))) %>%
  ungroup()