首页 > 解决方案 > 使用 dplyr 按组查找间隔

问题描述

在这个例子中,我有一个带有两个变量的小标题:

set.seed(123)
df <- tibble(gr = rep(1:3, each = 10), 
             val = gr + rnorm(30))

目标

我想生成val使用该函数的离散版本,findInterval但断点应该是gr特定的,因为在我的实际数据以及本示例中,分布val取决于gr. 使用 的四分位数在每组内确定断点val

我做了什么

我首先构造一个嵌套的 tibble,其中包含每个值的断点向量gr

df_breakpoints <- bind_cols(gr = 1:3, 
                            purrr::map_dfr(1:3, function(gr) {
                              c(-Inf, quantile(df$val[df$gr == gr], c(0.25, 0.5, 0.75)), Inf)
                              })) %>% 
  nest(bp = -gr) %>% 
  mutate(bp = purrr::map(.$bp, unlist))

然后我加入它df

df <- inner_join(df, df_breakpoints, by = "gr")

我定义离散变量的第一个猜测lvl

df %>% mutate(lvl = findInterval(x = val, vec = bp))

它产生错误

Error : Problem with `mutate()` input `lvl2`.
x 'vec' must be sorted non-decreasingly and not contain NAs
ℹ Input `lvl` is `findInterval(x = val, vec = bp)`.

然后我尝试了

df$lvl <- purrr::imap_dbl(1:nrow(df),
                               ~findInterval(x = df$val[.x], vec = df$bp[[.x]]))

或者

df %>% mutate(lvl = purrr::map2_int(df$val, df$bp, findInterval))

它确实有效。然而,它是非常低效的。使用我的实际数据(120 万行)需要几分钟才能运行。我想有比在行上迭代更好的方法。任何想法?

标签: rdplyr

解决方案


您可以在group_by+mutate步骤中执行此操作 -

library(dplyr)

df %>%
  group_by(gr) %>%
  mutate(breakpoints = findInterval(val, 
                       c(-Inf, quantile(val, c(0.25, 0.5, 0.75)), Inf))) %>%
  ungroup

#      gr    val breakpoints
#   <int>  <dbl>       <int>
# 1     1  0.440           1
# 2     1  0.770           2
# 3     1  2.56            4
# 4     1  1.07            3
# 5     1  1.13            3
# 6     1  2.72            4
# 7     1  1.46            4
# 8     1 -0.265           1
# 9     1  0.313           1
#10     1  0.554           2
# … with 20 more rows

findInterval分别适用于每个gr


推荐阅读