在dplyr中按组查找最接近x的值

8
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
4个回答

14

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()函数,并且每个组只有一个值是可以接受的,那么您可以将它包装在一个summarize函数中,以便它将被应用到每个组,并且根据?nth(),您还需要将该向量作为参数传递给函数:
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

11

有几种方法可以实现这个目标。

这里是一个 dplyr 的解决方案(通过使用这个答案找到):

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

这是一个巧妙的 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))] ),] - thelatemail
1
喜欢使用dplyr的slice函数! - TheSciGuy

5

离你所拥有的不太远

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

3
这是一个使用 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接