【问题标题】:Finding ALL duplicate rows, including "elements with smaller subscripts"查找所有重复行,包括“具有较小下标的元素”
【发布时间】:2011-12-12 20:33:36
【问题描述】:

R 的duplicated 返回一个向量,显示向量或数据框的每个元素是否是具有较小下标的元素的副本。所以如果 5 行数据帧的第 3、4 和 5 行相同,duplicated 会给我向量

FALSE, FALSE, FALSE, TRUE, TRUE

但在这种情况下,我实际上想要得到

FALSE, FALSE, TRUE, TRUE, TRUE

也就是说,我想知道一行是否也被带有更大下标的行所复制。

【问题讨论】:

    标签: r duplicates r-faq


    【解决方案1】:

    duplicated 有一个 fromLast 参数。 ?duplicated 的“示例”部分向您展示了如何使用它。只需调用duplicated 两次,一次是fromLast=FALSE,一次是fromLast=TRUE,然后取TRUE 所在的行。


    一些迟到的编辑: 您没有提供可重现的示例,因此这是由@jbaums 提供的插图

    vec <- c("a", "b", "c","c","c") 
    vec[duplicated(vec) | duplicated(vec, fromLast=TRUE)]
    ## [1] "c" "c" "c"
    

    编辑:还有一个数据框的例子:

    df <- data.frame(rbind(c("a","a"),c("b","b"),c("c","c"),c("c","c")))
    df[duplicated(df) | duplicated(df, fromLast=TRUE), ]
    ##   X1 X2
    ## 3  c  c
    ## 4  c  c
    

    【讨论】:

    • 等一下,我刚刚进行了测试,发现我错了:x &lt;- c(1:9, 7:10, 5:22); y &lt;- c(letters, letters[1:5]); test &lt;- data.frame(x, y); test[duplicated(test$x) | duplicated(test$x, fromLast=TRUE), ] 退回了所有 7、8 和 9 的三个副本。为什么会这样?
    • 因为无论你是从头开始还是从前面开始,都会捕获中间的。例如,duplicated(c(1,1,1))duplicated(c(1,1,1,), fromLast = TRUE) 给出 c(FALSE,TRUE,TRUE)c(TRUE,TRUE,FALSE)。在这两种情况下,中间值为TRUE。取两个向量的| 得到c(TRUE,TRUE,TRUE)
    【解决方案2】:

    您需要组装duplicated 值的集合,应用unique,然后使用%in% 进行测试。与往常一样,一个示例问题将使这个过程变得活跃。

    > vec <- c("a", "b", "c","c","c")
    > vec[ duplicated(vec)]
    [1] "c" "c"
    > unique(vec[ duplicated(vec)])
    [1] "c"
    >  vec %in% unique(vec[ duplicated(vec)]) 
    [1] FALSE FALSE  TRUE  TRUE  TRUE
    

    【讨论】:

    • 同意。甚至可能会减慢处理速度,但不太可能减慢速度。
    • 非常正确。 OP 没有提供数据示例来测试数据框中的“曾经重复”的行。我认为我使用duplicatedunique%in% 的建议可以很容易地推广到一个数据框,如果一个人首先paste 每一行都有一个不寻常的分隔符。 (接受的答案更好。)
    【解决方案3】:

    可以使用dplyr 获得数据框中的重复行

    library(tidyverse)
    df = bind_rows(iris, head(iris, 20)) # build some test data
    df %>% group_by_all() %>% filter(n()>1) %>% ungroup()
    

    要排除某些列 group_by_at(vars(-var1, -var2)) 可以改为对数据进行分组。

    如果实际需要行索引而不仅仅是数据,您可以先添加它们,如下所示:

    df %>% add_rownames %>% group_by_at(vars(-rowname)) %>% filter(n()>1) %>% pull(rowname)
    

    【讨论】:

    • 很好地使用了n()。不要忘记取消组合生成的数据框。
    • @qwr 我已调整答案以取消组合结果
    • @HolgerBrandl,@qwr,一般答案很有用,但我不明白如何选择要排除的列。 group_by_at(vars(-var1, -var2)) 中的“vars”指的是什么? var1var2 列名称是否在名为 vars 的数据表中?我认为负号表示排斥,对吗?所以剩下的过程(filterungroup)作用于数据表vars 中的其余列,但不包括var1var2,对吗?很抱歉这么迂腐,但我经常在速记方面遇到问题!
    • vars 是 dplyr 中的一个方法,参见 dplyr.tidyverse.org/reference/vars.html 。 var1, var2 确实是指要从重复检查中排除的列名。对建议解决方案中的分组变量进行重复评估。事实上,否定意味着排斥。
    • group_by_all()group_by_at() 在 dplyr 的最新版本中已被取代。现在你可以这样做了:iris %&gt;% group_by(across()) %&gt;% filter(n() &gt; 1) %&gt;% ungroup()
    【解决方案4】:

    我有same question,如果我没记错的话,这也是一个答案。

    vec[col %in% vec[duplicated(vec$col),]$col]
    

    不知道哪个更快,但我目前使用的数据集不够大,无法进行会产生显着时间间隔的测试。

    【讨论】:

    • 这个答案似乎使用vec 作为原子向量和数据框。我怀疑使用实际的 datframe 会失败。
    【解决方案5】:

    这是@Joshua Ulrich 作为函数的解决方案。这种格式允许您以与使用 duplicated() 相同的方式使用此代码:

    allDuplicated <- function(vec){
      front <- duplicated(vec)
      back <- duplicated(vec, fromLast = TRUE)
      all_dup <- front + back > 0
      return(all_dup)
    }
    

    用同样的例子:

    vec <- c("a", "b", "c","c","c") 
    allDuplicated(vec) 
    [1] FALSE FALSE  TRUE  TRUE  TRUE
    
    

    【讨论】:

      【解决方案6】:

      我遇到了类似的问题,但我需要通过特定列中的值来识别重复的行。我想出了以下 dplyr 解决方案:

      df <- df %>% 
        group_by(Column1, Column2, Column3) %>% 
        mutate(Duplicated = case_when(length(Column1)>1 ~ "Yes",
                                  TRUE ~ "No")) %>%
        ungroup()
      

      代码按特定列对行进行分组。如果组的长度大于 1,则代码会将组中的所有行标记为重复。完成后,您可以使用Duplicated 列进行过滤等。

      【讨论】:

        【解决方案7】:

        如果您对某些列的重复行感兴趣,可以使用 plyr 方法:

        ddply(df, .(col1, col2), function(df) if(nrow(df) > 1) df else c())
        

        使用 dplyr 添加计数变量:

        df %>% add_count(col1, col2) %>% filter(n > 1)  # data frame
        df %>% add_count(col1, col2) %>% select(n) > 1  # logical vector
        

        对于重复行(考虑所有列):

        df %>% group_by_all %>% add_tally %>% ungroup %>% filter(n > 1)
        df %>% group_by_all %>% add_tally %>% ungroup %>% select(n) > 1
        

        这些方法的好处是您可以指定多少重复作为截止值。

        【讨论】:

          【解决方案8】:

          这更新了@Holger Brandl 的答案以反映 dplyr 的最新版本(例如 1.0.5),其中 group_by_all()group_by_at() 已被取代。帮助文档建议改用across()

          因此,要获取所有重复的行,您可以执行以下操作: iris %&gt;% group_by(across()) %&gt;% filter(n() &gt; 1) %&gt;% ungroup()

          要包含此类行的索引,请添加“rowid”列,但将其从分组中排除: iris %&gt;% rowid_to_column() %&gt;% group_by(across(!rowid)) %&gt;% filter(n() &gt; 1) %&gt;% ungroup()

          在上面添加%&gt;% pull(rowid),你会得到一个索引向量。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-11
            • 2022-12-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多