ITPub博客

首页 > > > 利用Tidyverse(dplyr)来构造函数

利用Tidyverse(dplyr)来构造函数

作者:浪花小雨滴 时间:2019-07-31 11:25:19 0 删除 编辑

作者:黄天元,复旦大学博士在读,热爱数据科学与开源工具(R),致力于利用数据科学迅速积累行业经验优势和科学知识发现,涉猎内容包括但不限于信息计量、机器学习、数据可视化、应用统计建模、知识图谱等。知乎专栏:R语言数据挖掘。邮箱:huang.tian-yuan@qq.com.欢迎合作交流。


用Tidyverse一时爽,一直用Tidyverse一直爽。不过有的时候需要自己用函数,会发现Tidyverse编写函数有bug,比如函数里面的参数包含你在后面要select或者group_by的参数,就会报错。关于这个为的解决,官网上已经有帖子进行解释说明,并给出方案:

Programming with dplyr​dplyr.tidyverse.org图标

在2019年国际R会中Lionel Henry的报告提到了这个问题,并用更加好的方法解决了这个问题。Programming with dplyr在2019年国际R会中Lionel Henry的报告提到了这个问题,并用更加好的方法解决了这个问题。

http:///static/pres/t257103.pdf​

这里举个例子,直接给出最佳的解决方案:

1、数据,直接用R包的diamond数据集,看看大致数据结构:

> diamonds
# A tibble: 53,940 x 10
   carat cut       color clarity depth table price     x     y     z
   <dbl> <ord>     <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
 1 0.23  Ideal     E     SI2      61.5    55   326  3.95  3.98  2.43
 2 0.21  Premium   E     SI1      59.8    61   326  3.89  3.84  2.31
 3 0.23  Good      E     VS1      56.9    65   327  4.05  4.07  2.31
 4 0.290 Premium   I     VS2      62.4    58   334  4.2   4.23  2.63
 5 0.31  Good      J     SI2      63.3    58   335  4.34  4.35  2.75
 6 0.24  Very Good J     VVS2     62.8    57   336  3.94  3.96  2.48
 7 0.24  Very Good I     VVS1     62.3    57   336  3.95  3.98  2.47
 8 0.26  Very Good H     SI1      61.9    55   337  4.07  4.11  2.53
 9 0.22  Fair      E     VS2      65.1    61   337  3.87  3.78  2.49
10 0.23  Very Good H     VS1      59.4    61   338  4     4.05  2.39
# ... with 53,930 more rows

2、确定函数功能:对diamond中的数据,按照by来进行分组,然后对var变量进行求均值,得到的列重新命名为var_name(默认值为“avg”):

group_mean <- function(data, var, by, var_name = "avg") {
  data %>%
    group_by({{ by }}) %>%
    summarise(!!var_name := mean({{ var }}, na.rm = TRUE))
}

3、测试:

> diamonds %>% group_mean(price, by = cut, var_name = "price")
# A tibble: 5 x 2
  cut       price
  <ord>     <dbl>
1 Fair      4359.
2 Good      3929.
3 Very Good 3982.
4 Premium   4584.
5 Ideal     3458.

4、点评:与传统方法不一样的地方,首先var和by参数必须用双大括号({{}}),而给新列命名的方法则还是与之前的说法一样(先对字符变量用双叹号!!,命名的时候使用:=)。

考虑到性能的问题,其实可以使用data.table代码重写,重写函数如下:

group_mean <- function(data, var, by, var_name = "avg") {
  data %>%
    as.data.table() %>% 
    .[,.(mean(.SD[[var]]),na.rm = T),by]
}

diamonds %>% group_mean("price", by = "cut", var_name = "price")

其中的问题只有一个,就是变量名称要以字符型进行输入。如果不想的话,就要对任意变量在函数内先进行转换,把变量转化为字符。这个方法参考:

How to convert variable (object) name into String​stackoverflow.com图标

函数如下:

myfunc <- function(v1) {
  deparse(substitute(v1))
}

需要注意的是,这个函数的调用不能使用%>%(即不可以写v1 %>% myfunc),必须是myfunc(v1)。这里还没有涉及多个变量作为输入的情况(...),这个坑有空再过来填。


补一个新的博客文章:

Practical Tidy Evaluation​jessecambon.github.io图标

经典例子:

library(ggplot2)
scatter_plot <- function(df,x_var,y_var) {
  x_var <- enquo(x_var)
  y_var <- enquo(y_var)
  
  return(ggplot(data=df,aes(x=!!x_var,y=!!y_var)) + 
  geom_point() + theme_bw() + 
  theme(plot.title = element_text(lineheight=1, face="bold",hjust = 0.5)) +
  geom_smooth() +
  ggtitle(str_c(as_label(y_var), " vs. ",as_label(x_var)))
  )
}
scatter_plot(mtcars,disp,hp)

尽管如此,我建议写函数还是用字符来作为变量名称的输入,而不是直接使用变量。

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    39921