【问题标题】:Remove duplicates based on specific criteria根据特定条件删除重复项
【发布时间】:2014-03-14 08:18:56
【问题描述】:

我有一个如下所示的数据集:

df <- structure(list(Claim.Num = c(500L, 500L, 600L, 600L, 700L, 700L, 
100L, 200L, 300L), Amount = c(NA, 1000L, NA, 564L, 0L, 200L, 
NA, 0L, NA), Company = structure(c(NA, 1L, NA, 4L, 2L, 3L, NA, 
3L, NA), .Label = c("ATT", "Boeing", "Petco", "T Mobile"), class = "factor")), .Names =     
c("Claim.Num", "Amount", "Company"), class = "data.frame", row.names = c(NA, 
-9L))

我想根据 Claim Num 值删除重复行,但要根据以下条件删除重复行:df$Company == 'NA' | df$Amount == 0

换句话说,删除记录 1、3 和 5。

我已经走到这一步了:df &lt;- df[!duplicated(df$Claim.Num[which(df$Amount = 0 | df$Company == 'NA')]),]

代码运行没有错误,但实际上并未根据所需条件删除重复行。我认为这是因为我告诉它删除任何与这些标准匹配的重复索赔编号,但不要删除任何重复的Claim.Num,而是优先处理某些金额和公司以进行删除。请注意,我不能根据指定的值简单地过滤掉数据集,因为还有其他可能具有 0 或 NA 值的记录需要包含(例如,不应排除记录 8 和 9,因为它们的 Claim.Nums不重复)。

【问题讨论】:

    标签: r duplicates


    【解决方案1】:

    如果您先订购数据框,那么您可以确保 duplicated 保留您想要的:

    df.tmp <- with(df, df[order(ifelse(is.na(Company) | Amount == 0, 1, 0)), ])
    df.tmp[!duplicated(df.tmp$Claim.Num), ]
    #   Claim.Num Amount  Company
    # 2       500   1000      ATT
    # 4       600    564 T Mobile
    # 6       700    200    Petco
    # 7       100     NA     <NA>
    # 8       200      0    Petco
    # 9       300     NA     <NA>
    

    【讨论】:

    • 这适用于示例数据,但如果有一个额外的行 # 10 700 100 MyCo 具有相同的 Claim.Num 但没有 0 表示 Amount 或 NA 表示 Company。 (当然很容易解决。)
    • 那行得通。 @BrodieG 您能简要解释一下先排序然后删除重复项背后的原理吗?和0,1,0 订购金额?抱歉,我对duplicated 功能还不是很熟悉。
    • @MatthewLundberg 我的特定数据集没有超出规定标准的重复项,但很想知道您将如何处理这种情况以应对未来的此类操作。
    • @DaNiu, duplicated 将返回第一个之后重复的所有元素的索引。通过确保您要删除的不是第一个(即通过排序),我们可以保留其他的。
    【解决方案2】:

    略有不同的方法

    r <- merge(df,
               aggregate(df$Amount,by=list(Claim.Num=df$Claim.Num),length),
               by="Claim.Num")
    result <-r[!(r$x>1 & (is.na(r$Company) | (r$Amount==0))),-ncol(r)]
    result
    #   Claim.Num Amount  Company
    # 1       100     NA     <NA>
    # 2       200      0    Petco
    # 3       300     NA     <NA>
    # 5       500   1000      ATT
    # 7       600    564 T Mobile
    # 9       700    200    Petco
    

    这会添加一列 x 以指示哪些行多次出现 Claim.Num,然后根据您的条件过滤结果。使用-ncol(r) 只是删除了末尾的x 列。

    【讨论】:

      【解决方案3】:

      基于subset 和逻辑索引的另一种方式:

      subset(dat, !(duplicated(Claim.Num) | duplicated(Claim.Num, fromLast = TRUE)) |  
               (!is.na(Amount) & Amount))
      
        Claim.Num Amount  Company
      2       500   1000      ATT
      4       600    564 T Mobile
      6       700    200    Petco
      7       100     NA     <NA>
      8       200      0    Petco
      9       300     NA     <NA>
      

      【讨论】:

        猜你喜欢
        • 2020-03-27
        • 2015-04-20
        • 2017-11-26
        • 2020-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-27
        相关资源
        最近更新 更多