首页 > > > 利用Tidyverse(dplyr)来构造函数
作者:黄天元,复旦大学博士在读,热爱数据科学与开源工具(R),致力于利用数据科学迅速积累行业经验优势和科学知识发现,涉猎内容包括但不限于信息计量、机器学习、数据可视化、应用统计建模、知识图谱等。知乎专栏:R语言数据挖掘。邮箱:huang.tian-yuan@qq.com.欢迎合作交流。
用Tidyverse一时爽,一直用Tidyverse一直爽。不过有的时候需要自己用函数,会发现Tidyverse编写函数有bug,比如函数里面的参数包含你在后面要select或者group_by的参数,就会报错。关于这个为的解决,官网上已经有帖子进行解释说明,并给出方案:
Programming with dplyr
在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 rows2、确定函数功能:对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
函数如下:
myfunc <- function(v1) {
deparse(substitute(v1))
}需要注意的是,这个函数的调用不能使用%>%(即不可以写v1 %>% myfunc),必须是myfunc(v1)。这里还没有涉及多个变量作为输入的情况(...),这个坑有空再过来填。
补一个新的博客文章:
Practical Tidy Evaluation
经典例子:
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)尽管如此,我建议写函数还是用字符来作为变量名称的输入,而不是直接使用变量。
原文作者:;如有侵权,请联系管理员删除。