重复的行:根据条件选择行并存储重复的值

时间:2019-11-27 19:55:25

标签: r duplicates

我正在处理看起来像这样的原始数据集:

df <- data.frame("ID" = c("Alpha", "Alpha", "Alpha", "Alpha", 
                          "Beta","Beta", "Beta","Beta" ),
                 "treatment"= LETTERS[seq(from = 1, to = 8)],
                 "Year" = c(1970, 1970, 1980, 1990, 1970, 1980, 
                            1980,1990),
                 "Val" = c(0,0,0,1,0,1,0,1),
                 "Val2" = c(0,2.34,1.3,0,0,2.34,3.2,1.3))

数据有点脏,因为我对每个ID和Year标识符有多个观察结果-例如我在1970年的Alpha中有2个不同的行。在1980年的Beta中也是如此。

问题在于,感兴趣的变量Val Val2在重复的行中具有不同的分数(以id / year计)。

我想找到一种简洁的方法来产生以下最终数据帧:

final <- data.frame("ID" = c("Alpha", "Alpha", "Alpha", 
                             "Beta", "Beta","Beta" ),
                    "treatment"= c("B","C","D","E","G","H"),
                    "Year" = c(1970, 1980, 1990, 1970, 
                               1980,1990),
                    "Val" = c(0,0,1,0,0,1),
                    "Val2" = c(2.34,1.3,0,0,3.2,1.3),
                    "del_treat" = c("A",NA,NA,NA,"F",NA),
                    "del_Val"=c(0,NA,NA,NA,1,NA),
                    "del_Val2"=c(0,NA,NA,NA,2.34,NA))

逻辑如下:

1)我希望每个ID /年只有一个obs

2)我只想保留Val2类别中具有较高值的​​观察值。

3)我想将已删除的行值存储到单独的列中,以跟踪我要删除的内容del_treatdel_Valdel_Val2

进行说明。在df中,对Alpha / 1970有重复的观察。我想将其减少到一行。 Val2取值为0和2.34,在最终数据帧中,仅保留2.34。但是,处理A的值报告在新创建的列del_treatdel_Valdel_Val2中。

我能够根据Val2``setDT(df)[order(-Val2)][,.SD[1,], by = .(ID, Year)]选择行  值,但我想找到一种简洁的方法来将删除的结果也“存储”到新列中

2 个答案:

答案 0 :(得分:2)

这是dplyr的一个选项。按“ ID”,“年”分组后,创建一个逻辑列(ind),以检查“ Val2”的max,使用该列创建两个与“ Val”相对应的列,并以“ del”作为前缀那些消除的值以及不存在的“处理”,基于“ ind”和filter的行ungroup

library(dplyr)
df %>% 
   group_by(ID, Year) %>% 
   mutate(ind = Val2 == max(Val2) & !is.na(Val2)) %>% 
   mutate_at(vars(matches('Val')), 
        list(del = ~ if(any(!ind)) .[!ind] else NA_real_)) %>% 
   mutate(del_treat = if(any(!ind)) treatment[!ind] else NA_character_) %>% 
   filter(ind) %>%
   ungroup %>%
   select(-ind)

答案 1 :(得分:2)

使用data.table,根据rowid(ID, Year)降序排列,按Val2进行广播,除列名外,您都可以到达该列表。 “ _1”列是“ keep”列,而“ _2”列是“ del”列。

library(data.table)
setDT(df)

setorder(df, ID, Year, -Val2)

out <- 
  dcast(df, ID + Year ~ rowid(ID, Year), value.var = c('treatment', 'Val', 'Val2'))
out
#       ID Year treatment_1 treatment_2 Val_1 Val_2 Val2_1 Val2_2
# 1: Alpha 1970           B           A     0     0   2.34   0.00
# 2: Alpha 1980           C        <NA>     0    NA   1.30     NA
# 3: Alpha 1990           D        <NA>     1    NA   0.00     NA
# 4:  Beta 1970           E        <NA>     0    NA   0.00     NA
# 5:  Beta 1980           G           F     0     1   3.20   2.34
# 6:  Beta 1990           H        <NA>     1    NA   1.30     NA

我们可以更改名称以匹配您的名称,唯一的区别是del列的末尾有一个数字。如果每个组的行数大于2,将很有用。

setnames(out, function(x) gsub('(.*)_1', '\\1', x))
setnames(out, function(x) gsub('(.*_\\d+)', 'del_\\1', x))
out
#       ID Year treatment del_treatment_2 Val del_Val_2 Val2 del_Val2_2
# 1: Alpha 1970         B               A   0         0 2.34       0.00
# 2: Alpha 1980         C            <NA>   0        NA 1.30         NA
# 3: Alpha 1990         D            <NA>   1        NA 0.00         NA
# 4:  Beta 1970         E            <NA>   0        NA 0.00         NA
# 5:  Beta 1980         G               F   0         1 3.20       2.34
# 6:  Beta 1990         H            <NA>   1        NA 1.30         NA