【问题标题】:Subset with unique cases, based on multiple columns基于多列的具有独特案例的子集
【发布时间】:2012-07-07 08:53:29
【问题描述】:

我想对数据框进行子集化,以仅包含具有三列唯一组合的行。我的情况类似于this 问题中提出的情况,但我也想保留数据中的其他列。这是我的例子:

> df
  v1  v2  v3   v4  v5
1  7   1   A  100  98 
2  7   2   A   98  97
3  8   1   C   NA  80
4  8   1   C   78  75
5  8   1   C   50  62
6  9   3   C   75  75

请求的输出将是这样的,我正在寻找仅基于 v1、v2 和 v3 的独特案例:

> df.new
  v1  v2  v3   v4  v5
1  7   1   A  100  98 
2  7   2   A   98  97
3  8   1   C   NA  80
6  9   3   C   75  75

如果我能恢复非唯一行,那也太好了:

> df.dupes
  v1  v2  v3   v4  v5
3  8   1   C   NA  80
4  8   1   C   78  75
5  8   1   C   50  62

我在 sql (here) 中看到了一个有关如何执行此操作的相关问题,但我无法在 R 中解决此问题。我敢肯定它很简单,但使用 unique() 和 subset() 并没有卓有成效。提前致谢。

【问题讨论】:

    标签: r unique subset


    【解决方案1】:

    您可以使用duplicated() 函数查找唯一组合:

    > df[!duplicated(df[1:3]),]
      v1 v2 v3  v4 v5
    1  7  1  A 100 98
    2  7  2  A  98 97
    3  8  1  C  NA 80
    6  9  3  C  75 75
    

    要仅获取重复项,您可以双向检查:

    > df[duplicated(df[1:3]) | duplicated(df[1:3], fromLast=TRUE),]
      v1 v2 v3 v4 v5
    3  8  1  C NA 80
    4  8  1  C 78 75
    5  8  1  C 50 62
    

    【讨论】:

    • 第一部分有效,但第二部分只能恢复两个重复项(我编辑了示例以证明可以有两个以上的重复项)
    • @user1202761 你应该再试试 Ken 的代码。它为我返回所有三个重复的行。
    • @joran 你是对的!经过一番检查后发现我的数据不超过两个重复,这就是为什么我不能显示三个!感谢您的提醒。
    • 我不想就此提出新问题,所以:如何根据第 1 列和第 3 列而不是第 2 列来做同样的事情?我尝试了 1,3 而不是 1:3,但它不起作用。
    • @user3343907 像这样:df[!duplicated( df[c(1,3)] ), ]
    【解决方案2】:

    使用dplyr 你可以这样做:

    library(dplyr)
    
    # distinct
    df %>% 
      distinct(v1, v2, v3, .keep_all = T)
    
    # non-distinct only
    df %>% 
      group_by(v1, v2, v3) %>% 
      filter(n() > 1)
    
    # exclude any non-distinct
    df %>% 
      group_by(v1, v2, v3) %>% 
      filter(n() == 1)
    

    【讨论】:

    • 我要补充一点,distinct 将保留重复集的第一行并丢弃其余部分。没有进行平均或估算。
    【解决方案3】:

    您可以使用plyr 包:

    library(plyr)
    
    ddply(df, c("v1","v2","v3"), head, 1)
    #   v1 v2 v3  v4 v5
    # 1  7  1  A 100 98
    # 2  7  2  A  98 97
    # 3  8  1  C  NA 80
    # 4  9  3  C  75 75
    
    ddply(df, c("v1","v2","v3"), function(x) if(nrow(x)>1) x else NULL)
    #   v1 v2 v3 v4 v5
    # 1  8  1  C NA 80
    # 2  8  1  C 78 75
    # 3  8  1  C 50 62
    

    【讨论】:

      【解决方案4】:

      是的,但是如果数据太多,使用 plyr 和 ddply 会非常慢。

      你可以试试这种方法:

      df[ cbind( which(duplicated(df[1:3])), which(duplicated(df[1:3], fromLast=TRUE))),]
      

      或::

      from = which(duplicated(df[1:3])
      to = which(duplicated(df[1:3], fromLast=TRUE))
      df[cbind(from,to),]
      

      在大多数情况下会更快。

      测试一下并告诉我们

      有一些错误,但我猜你可以修复这些,只要你明白了。

      也尝试独特的和所有的

      【讨论】:

      • dplyr 基本上已经取代了 plyr 和 ddply,现在这两种语法都干净且合乎逻辑,并且运行速度比 base R 快。
      【解决方案5】:

      如果您使用的是data.table,就很容易对一个或多个变量产生独特的情况。语法如下

      unique(DT, by = c("var1", "var2"))
      

      【讨论】:

        【解决方案6】:

        一种不优雅但实用的方法是将给定行的条目粘贴在一起并查找哪些是唯一(或非唯一)行,例如:

        df.vector=apply(df,1,FUN=function(x) {paste(x,collapse="")})
        df.table=table(df.vector)
        

        然后使用以下内容获取重复项的索引:

        which(df.vector%in%names(which(df.table>1)))
        

        【讨论】:

          【解决方案7】:

          我知道这是一个非常古老的问题,但无论如何我认为使用 unique() 函数的明显解决方案也应该在这里提出:

          unique(df[1:3])
          

          或按名称指定列:

          unique(df[c("v1","v2","v3)]
          

          ...并指定行:

          unique(df[,c("v1","v2","v3)]
          

          【讨论】:

            猜你喜欢
            • 2021-04-01
            • 1970-01-01
            • 2019-04-17
            • 1970-01-01
            • 1970-01-01
            • 2015-10-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多