使用 dplyr 和 group_by 编写自己的函数 - 如何继续更改列名
Writing own function using dplyr and group_by - how to continue with changed column names
我想制作 table 用于给出观察次数的出版物,按两个变量分组。这个代码工作正常。但是,在尝试将其转换为函数时,我遇到了 运行 问题。
我正在使用 dplyr_0.7.2
使用 mtcars 的示例:
函数外 table 的代码:有效
library(tidyverse)
tab1 <- mtcars %>% count(cyl) %>% rename(Total = n)
tab2 <- mtcars %>%
group_by(cyl, gear) %>% count %>%
spread(gear, n)
tab <- full_join(tab1, tab2, by = "cyl")
tab
# This is the output (which is what I want)
A tibble: 3 x 5
cyl Total `3` `4` `5`
<dbl> <int> <int> <int> <int>
1 4 11 1 8 2
2 6 7 2 4 1
3 8 14 12 NA 2
尝试将其放入函数中
tab1 的功能:有效
count_by_two_groups_A <- function(df, var1){
var1 <- enquo(var1)
tab1 <- df %>% count(!!var1) %>% rename(Total = n)
tab1
}
count_by_two_groups_A(mtcars, cyl)
A tibble: 3 x 2
cyl Total
<dbl> <int>
1 4 11
2 6 7
3 8 14
tab2 第一部分的功能:到此为止,但是...
count_by_two_groups_B <- function(df, var1, var2){
var1 <- enquo(var1)
var2 <- enquo(var2)
tab2 <- df %>% group_by((!!var1), (!!var2)) %>% count
tab2
}
count_by_two_groups_B(mtcars, cyl, gear)
A tibble: 8 x 3
Groups: (cyl), (gear) [8]
`(cyl)` `(gear)` n
<dbl> <dbl> <int>
1 4 3 1
2 4 4 8
3 4 5 2
4 6 3 2
5 6 4 4
6 6 5 1
7 8 3 12
8 8 5 2
列名称已更改为 (cyl) 和 (gear)。既然列名已经更改,我似乎无法弄清楚如何继续使用 spread() 和 full_join() (或使用新列名的任何其他内容)。 IE。我不知道如何以整齐的方式指定新的列名,以便能够继续。我尝试了各种方法,但都没有成功。
我可以让它与 NSE(非标准评估)一起工作。无法使用 tidyverse 来完成,因为我没有安装它,也懒得安装。
这是一个工作代码:
library(dplyr)
library(tidyr)
count_by_two_groups_B <- function(df, var1, var2){
# var1 <- enquo(var1)
# var2 <- enquo(var2)
tab2 <- df %>% group_by_(var1, var2) %>% summarise(n = n() ) %>%spread(gear, n)
tab2
}
count_by_two_groups_B(mtcars, 'cyl', 'gear')
结果:
# A tibble: 3 x 4
# Groups: cyl [3]
cyl `3` `4` `5`
* <dbl> <int> <int> <int>
1 4 1 8 2
2 6 2 4 1
3 8 12 NA 2
在这种情况下,使用 dplyr 或 tidyverse 似乎有些过分。有基本功能可以做到这一点...... table
并以长格式生成结果,as.dataframe
:
as.data.frame( with(mtcars, table(cyl,gear)) , responseName="Total")
#--------
cyl gear Total
1 4 3 1
2 6 3 2
3 8 3 12
4 4 4 8
5 6 4 4
6 8 4 0
7 4 5 2
8 6 5 1
9 8 5 2
这将是一种 dplyr 方法:
mtcars %>% group_by(cyl,gear) %>% summarise(Total=n())
#----
# A tibble: 8 x 3
# Groups: cyl [?]
cyl gear Total
<dbl> <dbl> <int>
1 4 3 1
2 4 4 8
3 4 5 2
4 6 3 2
5 6 4 4
6 6 5 1
7 8 3 12
8 8 5 2
如果问题是如何将其作为 table 对象获取(认为这可能是您使用 spread
的目标,那么只需:
with(mtcars, table(cyl,gear))
在潮汐上下文中设置名称的常用方法是使用定义运算符 :=
。它看起来像这样:
df %>%
group_by(
!! nm1 := !! var1,
!! nm2 := !! var2
) %>%
count()
为此,您需要从 var1
中提取 nm1
。不幸的是,我还没有一种简单的方法来去除括号中的内容。我认为在即将到来的函数 ensym()
中这样做是有意义的(它捕获符号而不是 quosures 并在您提供调用时发出错误)。我在这里提交了一张票:https://github.com/tidyverse/rlang/issues/223
幸运的是,我们这里有两个简单的解决方案。首先请注意,您不需要括号。仅当捕获的表达式中涉及其他运算符时才需要它们。例如。在这些情况下:
(!! var) / avg
(!! var) < value
在这种情况下,如果您省略了括号,!!
将尝试取消对整个表达式的引用,而不仅仅是一个符号。另一方面,在您的函数中没有运算符,因此您可以安全地取消引用而不包含:
count_by_two_groups_B <- function(df, var1, var2) {
var1 <- enquo(var1)
var2 <- enquo(var2)
df %>%
group_by(!! var1, !! var2) %>%
count()
}
最后,您可以通过允许可变数量的参数使您的函数更通用。这更容易实现,因为点是 forwarded 所以不需要捕获和取消引用。只需将它们传递给 group_by()
:
count_by <- function(df, ...) {
df %>%
group_by(...) %>%
count()
}
我想制作 table 用于给出观察次数的出版物,按两个变量分组。这个代码工作正常。但是,在尝试将其转换为函数时,我遇到了 运行 问题。
我正在使用 dplyr_0.7.2
使用 mtcars 的示例:
函数外 table 的代码:有效
library(tidyverse)
tab1 <- mtcars %>% count(cyl) %>% rename(Total = n)
tab2 <- mtcars %>%
group_by(cyl, gear) %>% count %>%
spread(gear, n)
tab <- full_join(tab1, tab2, by = "cyl")
tab
# This is the output (which is what I want)
A tibble: 3 x 5
cyl Total `3` `4` `5`
<dbl> <int> <int> <int> <int>
1 4 11 1 8 2
2 6 7 2 4 1
3 8 14 12 NA 2
尝试将其放入函数中
tab1 的功能:有效
count_by_two_groups_A <- function(df, var1){
var1 <- enquo(var1)
tab1 <- df %>% count(!!var1) %>% rename(Total = n)
tab1
}
count_by_two_groups_A(mtcars, cyl)
A tibble: 3 x 2
cyl Total
<dbl> <int>
1 4 11
2 6 7
3 8 14
tab2 第一部分的功能:到此为止,但是...
count_by_two_groups_B <- function(df, var1, var2){
var1 <- enquo(var1)
var2 <- enquo(var2)
tab2 <- df %>% group_by((!!var1), (!!var2)) %>% count
tab2
}
count_by_two_groups_B(mtcars, cyl, gear)
A tibble: 8 x 3
Groups: (cyl), (gear) [8]
`(cyl)` `(gear)` n
<dbl> <dbl> <int>
1 4 3 1
2 4 4 8
3 4 5 2
4 6 3 2
5 6 4 4
6 6 5 1
7 8 3 12
8 8 5 2
列名称已更改为 (cyl) 和 (gear)。既然列名已经更改,我似乎无法弄清楚如何继续使用 spread() 和 full_join() (或使用新列名的任何其他内容)。 IE。我不知道如何以整齐的方式指定新的列名,以便能够继续。我尝试了各种方法,但都没有成功。
我可以让它与 NSE(非标准评估)一起工作。无法使用 tidyverse 来完成,因为我没有安装它,也懒得安装。
这是一个工作代码:
library(dplyr)
library(tidyr)
count_by_two_groups_B <- function(df, var1, var2){
# var1 <- enquo(var1)
# var2 <- enquo(var2)
tab2 <- df %>% group_by_(var1, var2) %>% summarise(n = n() ) %>%spread(gear, n)
tab2
}
count_by_two_groups_B(mtcars, 'cyl', 'gear')
结果:
# A tibble: 3 x 4
# Groups: cyl [3]
cyl `3` `4` `5`
* <dbl> <int> <int> <int>
1 4 1 8 2
2 6 2 4 1
3 8 12 NA 2
在这种情况下,使用 dplyr 或 tidyverse 似乎有些过分。有基本功能可以做到这一点...... table
并以长格式生成结果,as.dataframe
:
as.data.frame( with(mtcars, table(cyl,gear)) , responseName="Total")
#--------
cyl gear Total
1 4 3 1
2 6 3 2
3 8 3 12
4 4 4 8
5 6 4 4
6 8 4 0
7 4 5 2
8 6 5 1
9 8 5 2
这将是一种 dplyr 方法:
mtcars %>% group_by(cyl,gear) %>% summarise(Total=n())
#----
# A tibble: 8 x 3
# Groups: cyl [?]
cyl gear Total
<dbl> <dbl> <int>
1 4 3 1
2 4 4 8
3 4 5 2
4 6 3 2
5 6 4 4
6 6 5 1
7 8 3 12
8 8 5 2
如果问题是如何将其作为 table 对象获取(认为这可能是您使用 spread
的目标,那么只需:
with(mtcars, table(cyl,gear))
在潮汐上下文中设置名称的常用方法是使用定义运算符 :=
。它看起来像这样:
df %>%
group_by(
!! nm1 := !! var1,
!! nm2 := !! var2
) %>%
count()
为此,您需要从 var1
中提取 nm1
。不幸的是,我还没有一种简单的方法来去除括号中的内容。我认为在即将到来的函数 ensym()
中这样做是有意义的(它捕获符号而不是 quosures 并在您提供调用时发出错误)。我在这里提交了一张票:https://github.com/tidyverse/rlang/issues/223
幸运的是,我们这里有两个简单的解决方案。首先请注意,您不需要括号。仅当捕获的表达式中涉及其他运算符时才需要它们。例如。在这些情况下:
(!! var) / avg
(!! var) < value
在这种情况下,如果您省略了括号,!!
将尝试取消对整个表达式的引用,而不仅仅是一个符号。另一方面,在您的函数中没有运算符,因此您可以安全地取消引用而不包含:
count_by_two_groups_B <- function(df, var1, var2) {
var1 <- enquo(var1)
var2 <- enquo(var2)
df %>%
group_by(!! var1, !! var2) %>%
count()
}
最后,您可以通过允许可变数量的参数使您的函数更通用。这更容易实现,因为点是 forwarded 所以不需要捕获和取消引用。只需将它们传递给 group_by()
:
count_by <- function(df, ...) {
df %>%
group_by(...) %>%
count()
}