Hadley说,“每当你复制并粘贴一段代码超过两次时,你应该考虑编写一个函数” - 我经常在dplyr中写这个链:
df %>%
group_by(col) %>%
summarise(n = n()) %>%
mutate(percent = round((n / sum(n)) * 100, 2) %>%
arrange(desc(n))
我想用两个参数创建一个函数:数据框和变量或列名。这就是我现在正在尝试的事情:
value_counts = function(df, col) {
group_by_(df, col) %>%
summarise_(n = n()) %>%
mutate_(percent = round((n / sum(n)) * 100, 2)) %>%
arrange(desc(n))
}
它不起作用,我在本网站上尝试了其他一些建议,但我不太明白它们是如何工作的,例如:
value_counts = function(df, col) {
group_by_(df, .dots = col) %>%
summarise_(n = n()) %>%
mutate_(percent = round((n / sum(n)) * 100, 2)) %>%
arrange(desc(n))
}
我真的想编写一个使用管道并依赖于dplyr的函数。我可以继续编写一遍又一遍的代码,但我想开始在R中编写有用的函数以节省时间。
我是geom_text()的忠实粉丝,喜欢快速轻松地从数据框中获取dplyr中的信息,这样我就可以快速获得大量图表!
我应阅读的任何资源或其后的链接都会很有用。谢谢!
答案 0 :(得分:2)
当您将列名称作为字符串传递给它们时,仅将NSE函数替换为其标准等效函数。在您的情况下,仅在group_by_
函数中,col
是一个变量,假设您想要调用您的函数value_counts(df, "some_column")
。中间人n
和percent
不依赖于变量,因此根本不需要更改。
value_counts <- function(df, col) {
group_by_(df, col) %>%
summarise(n = n()) %>%
mutate(percent = round(n / sum(n) * 100, 2)) %>%
arrange(desc(n))
}
value_counts(iris, "Species")
答案 1 :(得分:2)
@ jenesaisquoi的答案很棒,但每当我编写dplyr
- y函数时,我都会尝试以与该软件包类似的方式编写它们。我想有一对SE和NSE函数,你可以使用裸变量名。
有几点需要注意。
%>%
),使它们更快,更容易调试。管道在交互式使用中非常方便,但我倾向于在编程功能时避免它们。::
。这意味着您现在无需加载dplyr
即可使用该功能。...
参数,接受根据需要分组的数量。vignette(NSE)
包的使用以及lazyeval
处理dplyr
和...
的方式的详细信息,请参阅.dots
。value_counts <- function(df, ...) {
value_counts_(df, .dots = lazyeval::lazy_dots(...))
}
value_counts_ <- function(df, ..., .dots) {
dots <- lazyeval::all_dots(.dots, ..., all_named = TRUE)
df <- dplyr::group_by_(df, .dots = dots)
df <- dplyr::summarise(df, n = n())
df <- dplyr::mutate(df, percent = round(n / sum(n) * 100, 2))
df <- dplyr::arrange(df, desc(n))
return(df)
}
value_counts(mtcars, cyl)
value_counts(mtcars, cyl, vs)
value_counts_(mtcars, ~cyl)
value_counts_(mtcars, ~cyl, ~vs)
value_counts_(mtcars, .dots = list(~cyl, ~vs))
你可以轻松地将它们与其他dplyr
动词一起管道:
library(dplyr)
mtcars %>%
filter(cyl != 4) %>%
value_counts()