【问题标题】:how to remove unique entry and keep duplicates in R如何删除唯一条目并在R中保留重复项
【发布时间】:2015-11-22 10:34:30
【问题描述】:
ID     Cat1  Cat2    Cat3   Cat4
A0001   358 11.25   37428   0
A0001   279 14.6875 38605   0
A0013   367 5.125   40152   1
A0014   337 16.3125 38624   0
A0020   367 8.875   37797   0
A0020   339 9.625   39324   0

我需要帮助学习如何删除文件中的唯一行,同时保留重复或三次。例如,输出应如下所示:

ID     Cat1  Cat2    Cat3   Cat4
A0001   358 11.25   37428   0
A0001   279 14.6875 38605   0
A0020   367 8.875   37797   0
A0020   339 9.625   39324   0

如果你能给我建议如何解决这个问题,非常感谢。

感谢大家的建议。我想计算重复测量(通过唯一 ID)之间不同类别(即 Cat2、Cat 3)中的值差异。将不胜感激任何建议。

【问题讨论】:

    标签: r


    【解决方案1】:

    base R 中的另一个选项使用duplicated

    dx[dx$ID %in% dx$ID[duplicated(dx$ID)],]
    
    #      ID Cat1    Cat2  Cat3 Cat4
    # 1 A0001  358 11.2500 37428    0
    # 2 A0001  279 14.6875 38605    0
    # 5 A0020  367  8.8750 37797    0
    # 6 A0020  339  9.6250 39324    0
    

    data.table 使用重复

    使用duplicated 和fromLast 获得的版本:

    library(data.table)
    setkey(setDT(dx),ID) # or with data.table 1.9.5+: setDT(dx,key="ID")
    dx[duplicated(dx) |duplicated(dx,fromLast=T)]
    
    #       ID Cat1    Cat2  Cat3 Cat4
    # 1: A0001  358 11.2500 37428    0
    # 2: A0001  279 14.6875 38605    0
    # 3: A0020  367  8.8750 37797    0
    # 4: A0020  339  9.6250 39324    0
    

    这也可以应用于基础 R,但我更喜欢 data.table 这里的语法糖。

    【讨论】:

    • 这个base 解决方案比其他答案中的解决方案快得多(没有尝试任何data.table 解决方案)。比 ave 快 6 倍,比 dplyr 快 14 倍。
    【解决方案2】:

    一般cmets。

    • ave 方法是这里唯一保留数据初始行顺序的方法。
    • by 方法应该非常慢。我怀疑在选择组时 data.table 和 dplyr 并不比 ave 和 tapply 快​​多少。欢迎使用基准来证明我的错误!

    base R(感谢@thelatemail 提供了前两种方法。)

    1) 为每一行分配其df$ID 组的长度,我们根据长度向量进行过滤。

    df[ ave(1:nrow(df), df$ID, FUN=length) > 1 , ]
    

    2) 或者,我们按df$ID 拆分行名或编号,选择要保留哪些组的行。 tapply 返回一组行的列表,因此我们必须将unlist 它们放入单个行向量中。

    df[ unlist(tapply(1:nrow(df), df$ID, function(x) if (length(x) > 1) x)) , ]
    

    以下是一种更糟糕的方法,但更好地与您在 data.table 和 dplyr 中看到的相似:

    3) 数据被df$ID 分割,保留每个数据子集,SD 如果有超过一行。 by 返回一个列表,因此我们必须将 rbind 重新组合在一起。

    do.call( rbind, c(list(make.row.names = FALSE),
        by(df, df$ID, FUN=function(SD) if (nrow(SD) > 1) SD )))
    

    data.table .N 对应于by=ID 组内的nrow;而.SD 是数据的子集。

    library(data.table)
    setDT(df)[, if (.N>1) .SD, by=ID]
    
    #       ID Cat1    Cat2  Cat3 Cat4
    # 1: A0001  358 11.2500 37428    0
    # 2: A0001  279 14.6875 38605    0
    # 3: A0020  367  8.8750 37797    0
    # 4: A0020  339  9.6250 39324    0
    

    dplyr n() 对应于group_by(ID) 组中的nrow。

    library(dplyr)
    df %>% group_by(ID) %>% filter( n() > 1 )
    
    # Source: local data frame [4 x 5]
    # Groups: ID
    # 
    #      ID Cat1    Cat2  Cat3 Cat4
    # 1 A0001  358 11.2500 37428    0
    # 2 A0001  279 14.6875 38605    0
    # 3 A0020  367  8.8750 37797    0
    # 4 A0020  339  9.6250 39324    0
    

    【讨论】:

    • 避免所有的拆分和行绑定,使用ave - dat[with(dat, ave(seq_along(ID),ID,FUN=length) )>1,]
    • @thelatemail 谢谢,这样更好。我已经用最高帐单对其进行了编辑。 [我稍微改了一下,这样当我提到ID 的使用方式时,很清楚我指的是代码的哪一部分(ave 的第二个参数。)]
    • @Frank - 你也可以通过 rownames - dat[unlist(tapply(rownames(dat), dat$ID, FUN=function(x) if(length(x)>1) x)),] 的子集来使 by / tapply 逻辑工作
    • @thelatemail 再次感谢。我已经添加并重新排列以适应顶部的一些评论。
    • 如果我想改变一下,只取每个唯一 ID 的第一行。有什么建议吗?
    【解决方案3】:

    我知道这是一个老问题,但我只是遇到了同样的问题,发现这个解决方案最简单:

    data<- data[duplicated(data$ID)]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-23
      • 2020-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多