【问题标题】:Filter groups that have a difference more than a specific value in R过滤组的差异大于 R 中的特定值
【发布时间】:2020-01-09 02:54:33
【问题描述】:

我实际上想按 v1 分组,只过滤 min(v3) 和 max(v3) 之间的差异大于 6 的那些 我有以下数据框

v1  v2  v3
a   2   13
b   5   3
c   2   1
d   2   1
e   1   2
a   2   4
a   8   1
e   1   9
b   0   1
c   2   8
d   1   5

如果我们计算一下,我们会发现:

a   “13-1”  =12
b   “3-1”   =2
c   “8-1”   =7
d   “5-1”   =4
e   “9-2”   =7

所以预期的结果是保持组 a、c 和 e 的值都为 >=6

v1  v2  v3
a   2   13
c   2   1
e   1   2
a   2   4
a   8   1
e   1   9
c   2   8

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我们可以在rangev3 值上使用group_by v1diff

    library(dplyr)
    df %>%  group_by(v1) %>% filter(diff(range(v3)) >= 6)
    
    #  v1       v2    v3
    #  <fct> <int> <int>
    #1 a         2    13
    #2 c         2     1
    #3 e         1     2
    #4 a         2     4
    #5 a         8     1
    #6 e         1     9
    #7 c         2     8
    

    或者我们也可以使用max - min

    df %>%  group_by(v1) %>%  filter(max(v3) - min(v3) >= 6)
    

    我们可以在base R中使用相同的ave

    subset(df, ave(v3, v1, FUN = function(x) diff(range(x))) >= 6)
    

    【讨论】:

      【解决方案2】:

      我们可以使用dplyr按'v1'分组,得到'v3'的rangedifference小于6

      library(dplyr)
      df1 %>%
        group_by(v1)%>%
        filter(abs(diff(range(v3))) >= 6)
      # A tibble: 7 x 3
      # Groups:   v1 [3]
      #  v1       v2    v3
      #  <chr> <int> <int>
      #1 a         2    13
      #2 c         2     1
      #3 e         1     2
      #4 a         2     4
      #5 a         8     1
      #6 e         1     9
      #7 c         2     8
      

      或者我们可以arrange 列'v3',然后filter firstlast 值的差异

      df1 %>% 
          arrange(v1, v3) %>% 
          group_by(v1) %>% 
          filter(last(v3)  - first(v3) >=6)
      

      或者data.table

      library(data.table)
      setDT(df1)[, .SD[abs(diff(range(v3))) >= 6], by = v1]
      

      或者另一个选项是.I

      setDT(df1)[df1[, .I[abs(diff(range(v3))) >= 6], by = v1]$V1]
      

      或者另一个选项是ave from base R

      i1 <- with(df1, ave(v3, v1, FUN = function(x) abs(diff(range(x)))) >= 6)
      df1[i1,]
      

      或者使用subsettapply

      subset(df1, v1 %in% names(which(tapply(v3, v1, 
                 function(x) diff(range(x))) >=6)))
      

      数据

      df1 <- structure(list(v1 = c("a", "b", "c", "d", "e", "a", "a", "e", 
      "b", "c", "d"), v2 = c(2L, 5L, 2L, 2L, 1L, 2L, 8L, 1L, 0L, 2L, 
      1L), v3 = c(13L, 3L, 1L, 1L, 2L, 4L, 1L, 9L, 1L, 8L, 5L)), 
      class = "data.frame", row.names = c(NA, 
      -11L))
      

      【讨论】:

      • 一个不需要子集.SDdata.table 替代方案将是dat[, if( abs(diff(range(v3))) &gt; 6) .SD, by=v1] - 我认为应该更多高效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-30
      • 2021-03-14
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      相关资源
      最近更新 更多