【问题标题】:find value closest to x by group in dplyr [duplicate]在dplyr中按组查找最接近x的值[重复]
【发布时间】:2017-04-11 15:47:57
【问题描述】:
library(dplyr)
a <- data_frame(id = c("A","A","A","B","B","B"),
                b = c(1.2, 1.5, 1.8, 1.1, 1.6, 1.4))

现在,我想为 id 中的每个类别检索最接近 1.43 的值。 我想我可以使用:

a %>% group_by(id) %>% nth(which.min(abs(.$b-1.43)))

但 dplyr 状态

Error: Don't know how to generate default for object of class grouped_df/tbl_df/tbl/data.frame

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    与你所拥有的相距不远

    a %>% group_by(id) %>% summarise(which.min(abs(b-1.43)))
    # A tibble: 2 × 2
    #      id `which.min(abs(b - 1.43))`
    #   <chr>                      <int>
    # 1     A                          2
    # 2     B                          3
    

    或者如果您需要值,而不是索引:

    a %>% group_by(id) %>% summarise(b[which.min(abs(b-1.43))])
    # A tibble: 2 × 2
    #      id `b[which.min(abs(b - 1.43))]`
    #   <chr>                         <dbl>
    # 1     A                           1.5
    # 2     B                           1.4
    

    【讨论】:

      【解决方案2】:

      有几种方法可以做到这一点。

      这是一个dplyr 解决方案(使用this answer 找到):

      a %>%
          group_by(id) %>%
          slice(which.min(abs(b - 1.43)))
      
           id     b
        <chr> <dbl>
      1     A   1.5
      2     B   1.4
      

      这是一个基本解决方案:

      do.call('rbind', by(a, a$id, function(x) x[which.min(abs(x$b - 1.43)), ]))
      
           id     b
        <chr> <dbl>
      1     A   1.5
      2     B   1.4
      

      这是一个 hacky dplyr 解决方案:

      a %>%
          mutate(AbsDiff = abs(b - 1.43)) %>%
          group_by(id) %>%
          mutate(AbsDiff_r = rank(AbsDiff, ties.method = 'first')) %>%
          filter(AbsDiff_r == 1)
      
           id     b AbsDiff AbsDiff_r
        <chr> <dbl>   <dbl>     <int>
      1     A   1.5    0.07         1
      2     B   1.4    0.03         1
      

      【讨论】:

      • 如果你想避免基本版本的do.call(rbind...,你也可以这样做:a[by(a, a$id, FUN=function(SD) rownames(SD)[which.min(abs(SD$b - 1.43))] ),]
      • 爱 dplyr slice!
      【解决方案3】:

      which.min() 返回数值(或逻辑)向量的(第一个)最小值或最大值的索引。 如果有多个彼此接近 1.43 的相等值并且您想要全部保留,可以使用filter()

      a %>% group_by(id) %>% filter(abs(b - 1.43) == min(abs(b - 1.43)))
      
      #Source: local data frame [2 x 2]
      #Groups: id [2]
      
      #     id     b
      #  <chr> <dbl>
      #1     A   1.5
      #2     B   1.4
      

      如果您更喜欢使用nth() 函数,并且每个组只有一个值是可以的,您可以将它包装在一个汇总函数中,以便将其应用于每个组,并且还根据@ 987654325@,您还需要将向量作为参数传递给函数:

      a %>% group_by(id) %>% summarise(b = nth(b, which.min(abs(b-1.43))))
      
      # A tibble: 2 × 2
      #     id     b
      #  <chr> <dbl>
      #1     A   1.5
      #2     B   1.4
      

      【讨论】:

        【解决方案4】:

        这是一个带有data.table的版本

        library(data.table)
        setDT(a)[, .(b= b[which.min(abs(b-1.43))]) , id]
        #  id   b
        #1:  A 1.5
        #2:  B 1.4
        

        【讨论】:

          猜你喜欢
          • 2015-07-26
          • 2021-12-26
          • 1970-01-01
          • 2015-08-03
          • 2021-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多