【问题标题】:find duplicate, compare a condition, erase one row r查找重复项,比较条件,删除一行 r
【发布时间】:2019-03-19 02:58:28
【问题描述】:

使用以下可重现的示例:

ID1<-c("a1","a4","a6","a6","a5", "a1" )
ID2<-c("b8","b99","b5","b5","b2","b8" )
Value1<-c(2,5,6,6,2,7)
Value2<- c(23,51,63,64,23,23)
Year<- c(2004,2004,2004,2004,2005,2004)
df<-data.frame(ID1,ID2,Value1,Value2,Year)

我想选择 ID1 和 ID2 以及 Year 在它们各自的列中具有相同值的行。对于这一行,我想比较重复行中的 Value1 和 Value2 ,如果值不同,则擦除具有较小值的行。

预期结果:

  ID1 ID2 Value1 Value2 Year         new

2  a4 b99      5     51 2004 a4_b99_2004

4  a6  b5      6     64 2004  a6_b5_2004
5  a5  b2      2     23 2005  a5_b2_2005
6  a1  b8      7     23 2004  a1_b8_2004

我尝试了以下方法: 查找我感兴趣的条件的唯一标识符

df$new<-paste(df$ID1,df$ID2, df$Year, sep="_")

我可以使用唯一标识符来查找数据库中包含重复项的行

IND<-which(duplicated(df$new) | duplicated(df$new, fromLast = TRUE))

在for循环中,如果唯一标识符重复比较值并删除行,但循环太复杂,我无法解决。

for (i in df$new) {

  if(sum(df$new == i)>1)
           {
  ind<-which(df$new==i)
  m= min(df$Value1[ind])
  df<-df[-which.min(df$Value1[ind]),]
  m= min(df$Value2[ind])
  df<-df[-which.min(df$Value2[ind]),]

  }
}

【问题讨论】:

    标签: r if-statement duplicates


    【解决方案1】:

    考虑aggregate 按您的分组、ID1ID2Year 检索最大值:

    df_new <- aggregate(.~ID1 + ID2 + Year, df, max)
    df_new
    
    #   ID1 ID2 Year Value1 Value2
    # 1  a6  b5 2004      6     64
    # 2  a1  b8 2004      7     23
    # 3  a4 b99 2004      5     51
    # 4  a5  b2 2005      2     23
    

    【讨论】:

    • 哇,非常优雅的解决方案!我希望不要忘记这一点!
    • 只有一个警告,它会删除带有“NA”的行,因此我添加了“na.action = na.pass”。但是仍然存在一个问题,它会删除只有一个 ID 具有“NA”的行
    • 我发布了另一个问题来用一个例子来解释这个问题stackoverflow.com/questions/52814300/…
    【解决方案2】:

    一些不同的可能性。使用dplyr

    df %>%
      group_by(ID1, ID2, Year) %>%
      filter(Value1 == max(Value1) & Value2 == max(Value2))
    

    或者:

    df %>%
      rowwise() %>%
      mutate(max_val = sum(Value1, Value2)) %>%
      ungroup() %>%
      group_by(ID1, ID2, Year) %>%
      filter(max_val == max(max_val)) %>%
      select(-max_val)
    

    使用data.table

    setDT(df)[df[, .I[Value1 == max(Value1) & Value2 == max(Value2)], by = list(ID1, ID2, Year)]$V1]
    

    或者:

    setDT(df)[, max_val := sum(Value1, Value2), by = 1:nrow(df)
       ][, filter := max_val == max(max_val), by = list(ID1, ID2, Year)
           ][filter != FALSE
             ][, -c("max_val", "filter")]
    

    或者:

    subset(setDT(df)[, max_val := sum(Value1, Value2), by = 1:nrow(df)
                 ][, filter := max_val == max(max_val), by = list(ID1, ID2, Year)], filter != FALSE)[, -c("max_val", "filter")]
    

    【讨论】:

    • 不错的方法集合,所有这些方法都只是擦除 NA...如果我想考虑它们怎么办?
    • 您的数据中没有 NA,您的意思是保留不符合您条件的案例吗?
    • 我没有在示例中添加 NA,但我的真实数据(不是年份)的所有列中都有 NA。
    • 对于值列,您可以使用 max(Value, na.rm = TRUE) 或者您可以将 NA 替换为 0(或其他选择值)。分配 ID 不是计算问题,而是概念问题。
    • 我认为在这种情况下它也是一个计算问题。如果我将 NA 更改为 ID 中的字符串,则在一年中有 NA 和其中一个 ID 的真实环时,它会重复。如果我保留 NA,它会在其中一个 ID 为 NA 时删除环。
    【解决方案3】:

    不加载库的解决方案:

                ID1 ID2 Value1 Value2 Year
    a6.b5.2004   a6  b5      6     64 2004
    a1.b8.2004   a1  b8      7     23 2004
    a4.b99.2004  a4 b99      5     51 2004
    a5.b2.2005   a5  b2      2     23 2005
    

    代码

    do.call(rbind, lapply(split(df, list(df$ID1, df$ID2, df$Year)),                  # make identifiers
                          function(x) {return(x[which.max(x$Value1 + x$Value2),])})) # take max of sum
    

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 2022-12-18
      • 2012-06-05
      • 2015-07-15
      • 2019-12-10
      • 2022-01-16
      相关资源
      最近更新 更多