将 dplyr quosure 自定义函数与 mutate_at 一起使用
Using dplyr quosure custom function with mutate_at
我正在尝试构建一个辅助函数来提取参数中给定列中的数字。我可以在 mutate
中使用我的函数(并对所有感兴趣的列重复它),但它似乎在 mutate_at
.
中不起作用
这是我的数据的示例:
> set.seed(20190928)
> evalYr <- 2018
> n <- 5
> (df <- data.frame(
+ AY = sample(2016:2019, n, replace = T),
+ Pay00 = rgamma(n, 2, 1/1000),
+ Pay01 = rgamma(n, 2, 1/1000),
+ Pay02 = rgamma(n, 2, 1/1000),
+ Pay03 = rgamma(n, 2, 1/1000)
+ ))
AY Pay00 Pay01 Pay02 Pay03
1 2018 2520.3772 2338.9490 919.8245 629.1657
2 2016 259.7804 1543.4450 661.6488 2382.7916
3 2018 2446.3075 312.5143 2297.9717 942.5627
4 2017 1386.6288 4179.0352 2370.2669 1846.5838
5 2018 541.8261 2104.4589 2622.1758 2606.0694
所以我已经构建(使用 dplyr
语法)这个帮助程序在我拥有的每个 PayXX
列上进行变异:
# Helper function to get the number inside column `PayXX` name
f1 <- function(pmt) enquo(pmt) %>% quo_name() %>% str_extract('(\d)+') %>% as.numeric()
此函数与 dplyr::mutate
一起工作正常:
> df %>% mutate(Pay00_numcol = f1(Pay00),
+ Pay01_numcol = f1(Pay01),
+ Pay02_numcol = f1(Pay02),
+ Pay03_numcol = f1(Pay03))
AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol Pay02_numcol Pay03_numcol
1 2018 2520.3772 2338.9490 919.8245 629.1657 0 1 2 3
2 2016 259.7804 1543.4450 661.6488 2382.7916 0 1 2 3
3 2018 2446.3075 312.5143 2297.9717 942.5627 0 1 2 3
4 2017 1386.6288 4179.0352 2370.2669 1846.5838 0 1 2 3
5 2018 541.8261 2104.4589 2622.1758 2606.0694 0 1 2 3
但是当我尝试在 mutate_at
中使用相同的函数时,它 returns NA 的:
> df %>% mutate_at(vars(starts_with('Pay')), list(numcol = ~f1(.)))
AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol Pay02_numcol Pay03_numcol
1 2018 2520.3772 2338.9490 919.8245 629.1657 NA NA NA NA
2 2016 259.7804 1543.4450 661.6488 2382.7916 NA NA NA NA
3 2018 2446.3075 312.5143 2297.9717 942.5627 NA NA NA NA
4 2017 1386.6288 4179.0352 2370.2669 1846.5838 NA NA NA NA
5 2018 541.8261 2104.4589 2622.1758 2606.0694 NA NA NA NA
有人遇到过类似的问题吗?在这种情况下,如何处理 mutate_at
函数?
谢谢,
可重现的例子
library(tidyverse)
library(stringr)
set.seed(20190928)
evalYr <- 2018
n <- 5
(df <- data.frame(
AY = sample(2016:2019, n, replace = T),
Pay00 = rgamma(n, 2, 1/1000),
Pay01 = rgamma(n, 2, 1/1000),
Pay02 = rgamma(n, 2, 1/1000),
Pay03 = rgamma(n, 2, 1/1000)
))
# Helper function to get the number inside column `PayXX` name
f1 <- function(pmt) enquo(pmt) %>% quo_name() %>% str_extract('(\d)+') %>% as.numeric()
# Working
df %>% mutate(Pay00_numcol = f1(Pay00),
Pay01_numcol = f1(Pay01),
Pay02_numcol = f1(Pay02),
Pay03_numcol = f1(Pay03))
# Not working
df %>% mutate_at(vars(starts_with('Pay')), list(numcol = ~f1(.)))
我想到的第一个方法是重塑数据可能更容易。但是,仍然需要一堆tidyr
函数才能得到1)一列"Pay00"、"Pay01"等; 2)提取数字; 3) 操纵所以你可以使用 tidyr::spread
回到宽形;和 4) 展开并删除我添加的“_value”位。
我相信最近版本的 tidyr
有更好的方法可以做到这一点,因为新的 pivot_wider
函数应该能够将多个列作为 value
。我完全没有弄乱这个,但也许其他人可以写出来。
library(tidyverse)
df %>%
rowid_to_column() %>%
gather(key, value, -AY, -rowid) %>%
mutate(numcol = as.numeric(str_extract(key, "\d+$"))) %>%
gather(key = coltype, value, value, numcol) %>%
unite(key, key, coltype) %>%
spread(key, value) %>%
select(AY, ends_with("value"), ends_with("numcol")) %>%
rename_all(str_remove, "_value")
#> AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol
#> 1 2018 2520.3772 2338.9490 919.8245 629.1657 0 1
#> 2 2016 259.7804 1543.4450 661.6488 2382.7916 0 1
#> 3 2018 2446.3075 312.5143 2297.9717 942.5627 0 1
#> 4 2017 1386.6288 4179.0352 2370.2669 1846.5838 0 1
#> 5 2018 541.8261 2104.4589 2622.1758 2606.0694 0 1
#> Pay02_numcol Pay03_numcol
#> 1 2 3
#> 2 2 3
#> 3 2 3
#> 4 2 3
#> 5 2 3
或者,如果您想坚持使用 tidyeval 方法:获取您正在调用函数的列的名称作为 quosures。请注意,如果您使用 list(numcol = ~f1(.))
表示法,所有这些 quosures 都会出现 .
f1 <- function(pmt) {
str_extract(rlang::as_name(enquo(pmt)), "\d+$") %>%
as.numeric()
}
df %>%
mutate_at(vars(starts_with("Pay")), list(numcol = f1))
# same output as prev
我正在尝试构建一个辅助函数来提取参数中给定列中的数字。我可以在 mutate
中使用我的函数(并对所有感兴趣的列重复它),但它似乎在 mutate_at
.
这是我的数据的示例:
> set.seed(20190928)
> evalYr <- 2018
> n <- 5
> (df <- data.frame(
+ AY = sample(2016:2019, n, replace = T),
+ Pay00 = rgamma(n, 2, 1/1000),
+ Pay01 = rgamma(n, 2, 1/1000),
+ Pay02 = rgamma(n, 2, 1/1000),
+ Pay03 = rgamma(n, 2, 1/1000)
+ ))
AY Pay00 Pay01 Pay02 Pay03
1 2018 2520.3772 2338.9490 919.8245 629.1657
2 2016 259.7804 1543.4450 661.6488 2382.7916
3 2018 2446.3075 312.5143 2297.9717 942.5627
4 2017 1386.6288 4179.0352 2370.2669 1846.5838
5 2018 541.8261 2104.4589 2622.1758 2606.0694
所以我已经构建(使用 dplyr
语法)这个帮助程序在我拥有的每个 PayXX
列上进行变异:
# Helper function to get the number inside column `PayXX` name
f1 <- function(pmt) enquo(pmt) %>% quo_name() %>% str_extract('(\d)+') %>% as.numeric()
此函数与 dplyr::mutate
一起工作正常:
> df %>% mutate(Pay00_numcol = f1(Pay00),
+ Pay01_numcol = f1(Pay01),
+ Pay02_numcol = f1(Pay02),
+ Pay03_numcol = f1(Pay03))
AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol Pay02_numcol Pay03_numcol
1 2018 2520.3772 2338.9490 919.8245 629.1657 0 1 2 3
2 2016 259.7804 1543.4450 661.6488 2382.7916 0 1 2 3
3 2018 2446.3075 312.5143 2297.9717 942.5627 0 1 2 3
4 2017 1386.6288 4179.0352 2370.2669 1846.5838 0 1 2 3
5 2018 541.8261 2104.4589 2622.1758 2606.0694 0 1 2 3
但是当我尝试在 mutate_at
中使用相同的函数时,它 returns NA 的:
> df %>% mutate_at(vars(starts_with('Pay')), list(numcol = ~f1(.)))
AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol Pay02_numcol Pay03_numcol
1 2018 2520.3772 2338.9490 919.8245 629.1657 NA NA NA NA
2 2016 259.7804 1543.4450 661.6488 2382.7916 NA NA NA NA
3 2018 2446.3075 312.5143 2297.9717 942.5627 NA NA NA NA
4 2017 1386.6288 4179.0352 2370.2669 1846.5838 NA NA NA NA
5 2018 541.8261 2104.4589 2622.1758 2606.0694 NA NA NA NA
有人遇到过类似的问题吗?在这种情况下,如何处理 mutate_at
函数?
谢谢,
可重现的例子
library(tidyverse)
library(stringr)
set.seed(20190928)
evalYr <- 2018
n <- 5
(df <- data.frame(
AY = sample(2016:2019, n, replace = T),
Pay00 = rgamma(n, 2, 1/1000),
Pay01 = rgamma(n, 2, 1/1000),
Pay02 = rgamma(n, 2, 1/1000),
Pay03 = rgamma(n, 2, 1/1000)
))
# Helper function to get the number inside column `PayXX` name
f1 <- function(pmt) enquo(pmt) %>% quo_name() %>% str_extract('(\d)+') %>% as.numeric()
# Working
df %>% mutate(Pay00_numcol = f1(Pay00),
Pay01_numcol = f1(Pay01),
Pay02_numcol = f1(Pay02),
Pay03_numcol = f1(Pay03))
# Not working
df %>% mutate_at(vars(starts_with('Pay')), list(numcol = ~f1(.)))
我想到的第一个方法是重塑数据可能更容易。但是,仍然需要一堆tidyr
函数才能得到1)一列"Pay00"、"Pay01"等; 2)提取数字; 3) 操纵所以你可以使用 tidyr::spread
回到宽形;和 4) 展开并删除我添加的“_value”位。
我相信最近版本的 tidyr
有更好的方法可以做到这一点,因为新的 pivot_wider
函数应该能够将多个列作为 value
。我完全没有弄乱这个,但也许其他人可以写出来。
library(tidyverse)
df %>%
rowid_to_column() %>%
gather(key, value, -AY, -rowid) %>%
mutate(numcol = as.numeric(str_extract(key, "\d+$"))) %>%
gather(key = coltype, value, value, numcol) %>%
unite(key, key, coltype) %>%
spread(key, value) %>%
select(AY, ends_with("value"), ends_with("numcol")) %>%
rename_all(str_remove, "_value")
#> AY Pay00 Pay01 Pay02 Pay03 Pay00_numcol Pay01_numcol
#> 1 2018 2520.3772 2338.9490 919.8245 629.1657 0 1
#> 2 2016 259.7804 1543.4450 661.6488 2382.7916 0 1
#> 3 2018 2446.3075 312.5143 2297.9717 942.5627 0 1
#> 4 2017 1386.6288 4179.0352 2370.2669 1846.5838 0 1
#> 5 2018 541.8261 2104.4589 2622.1758 2606.0694 0 1
#> Pay02_numcol Pay03_numcol
#> 1 2 3
#> 2 2 3
#> 3 2 3
#> 4 2 3
#> 5 2 3
或者,如果您想坚持使用 tidyeval 方法:获取您正在调用函数的列的名称作为 quosures。请注意,如果您使用 list(numcol = ~f1(.))
表示法,所有这些 quosures 都会出现 .
f1 <- function(pmt) {
str_extract(rlang::as_name(enquo(pmt)), "\d+$") %>%
as.numeric()
}
df %>%
mutate_at(vars(starts_with("Pay")), list(numcol = f1))
# same output as prev