首页 > 解决方案 > 数据框中的函数

问题描述

我想创建一个函数列表并将它们放在一个数据框中。它使我在余下的工作中更容易操作这些功能。我想在对字符/因子列进行分组时放置 ecdf 和分位数函数。

我做了这样的事情:

library(tidyverse)
quantilef = function(x) {
  qf = function(p){
    return(quantile(x, probs = p))
  }
  return(qf)
}

ecdfdf = iris %>%
  group_by(Species) %>%
  summarise(ecdf_ = list(ecdf(Sepal.Length)),
            qf_ = list(quantilef(x = Sepal.Length)))

ecdf 按预期工作:

> ecdfdf %>% mutate(p = map_dbl(.x = ecdf_, .f = ~.x(5)))
# A tibble: 3 x 4
  Species    ecdf_  qf_        p
  <fct>      <list> <list> <dbl>
1 setosa     <ecdf> <fn>    0.56
2 versicolor <ecdf> <fn>    0.06
3 virginica  <ecdf> <fn>    0.02

但是分位数给出NA

> ecdfdf %>% mutate(q10 = map_dbl(.x = qf_, .f = ~.x(0.5)))
# A tibble: 3 x 4
  Species    ecdf_  qf_      q10
  <fct>      <list> <list> <dbl>
1 setosa     <ecdf> <fn>      NA
2 versicolor <ecdf> <fn>      NA
3 virginica  <ecdf> <fn>      NA

我知道这是可行的quantilef,因为它在数据框之外工作:

> qfsl = quantilef(x = iris$Sepal.Length)
> qfsl(0.5)
50% 
5.8 

到底是怎么回事?我该如何解决这个问题?

标签: rtidyversetidyr

解决方案


我认为问题在于,当您为 创建函数列表时qf_,您正在传递一个参数,x该参数是延迟评估的。当你去调用函数时,x调用环境中不再存在。

解决此问题的一种方法是包装xquosure调用函数时对其进行评估的 a 。

这是一个代表:

library(tidyverse)

quantilef = function(x) {
  y <- rlang::new_quosure(x)
  qf <- function(p){
    return(quantile(rlang::eval_tidy(y), probs = p))
  }
  return(qf)
}

ecdfdf = iris %>%
  group_by(Species) %>%
  summarise(ecdf_ = list(ecdf(Sepal.Length)),
            qf_ = list(quantilef(x = Sepal.Length)))

ecdfdf %>% mutate(q10 = map_dbl(.x = qf_, .f = ~.x(0.5)))
#> # A tibble: 3 x 4
#>   Species    ecdf_  qf_      q10
#>   <fct>      <list> <list> <dbl>
#> 1 setosa     <ecdf> <fn>     5  
#> 2 versicolor <ecdf> <fn>     5.9
#> 3 virginica  <ecdf> <fn>     6.5

reprex 包(v0.3.0)于 2020-04-14 创建


推荐阅读