R dplyr:将函数用作下一列中的一列中的字符串
R dplyr: Use the function as a string in one column on the next column
我想使用 dplyr 将名称作为字符串存储在一列中的函数应用于另一列中的值。
我已经使用 mutate_
和 .dots
参数尝试了几件事,但我现在卡住了。
library(lubridate)
library(dplyr)
df <- data.frame(date=as.POSIXct('2017/01/01 12:34') + 1:10*123456,
fun=rep(c('minute','hour','day','month','year'),2))
输入:
> df
date fun
1 2017-01-02 22:51:36 minute
2 2017-01-04 09:09:12 hour
3 2017-01-05 19:26:48 day
4 2017-01-07 05:44:24 month
5 2017-01-08 16:02:00 year
6 2017-01-10 02:19:36 minute
7 2017-01-11 12:37:12 hour
8 2017-01-12 22:54:48 day
9 2017-01-14 09:12:24 month
10 2017-01-15 19:30:00 year
输出:
date fun res
1 2017-01-02 22:51:36 minute 51
2 2017-01-04 09:09:12 hour 9
3 2017-01-05 19:26:48 day 5
4 2017-01-07 05:44:24 month 1
5 2017-01-08 16:02:00 year 2017
6 2017-01-10 02:19:36 minute 19
7 2017-01-11 12:37:12 hour 12
8 2017-01-12 22:54:48 day 12
9 2017-01-14 09:12:24 month 1
10 2017-01-15 19:30:00 year 2017
我们可以使用mapply
df$res <- mapply(function(x,y) get(x)(y), as.character(df$fun), df$date)
df$res
#[1] 51 9 5 1 2017 19 12 12 1 2017
另一种选择是data.table
library(data.table)
setDT(df)[, res := as.integer(get(as.character(fun))(date)), 1:nrow(df)]
df
# date fun res
#1: 2017-01-02 22:51:36 minute 51
#2: 2017-01-04 09:09:12 hour 9
#3: 2017-01-05 19:26:48 day 5
#4: 2017-01-07 05:44:24 month 1
#5: 2017-01-08 16:02:00 year 2017
#6: 2017-01-10 02:19:36 minute 19
#7: 2017-01-11 12:37:12 hour 12
#8: 2017-01-12 22:54:48 day 12
#9: 2017-01-14 09:12:24 month 1
#10: 2017-01-15 19:30:00 year 2017
注意:无需额外努力创建查找表
您可以尝试使用 do.call
,但您必须使用 rowwise
:
library("dplyr")
library("lubridate")
df <- data.frame(
date = as.POSIXct('2017/01/01 12:34') + 1:10*123456,
fun = rep(c('minute','hour','day','month','year'),2),
stringsAsFactors = FALSE
)
df %>% rowwise() %>% mutate(res = as.character(do.call(fun, list(date))))
我能想到的一种方法是使用创建查找 table,然后使用 match
获取正确的输出格式
x <- c("minute", "hour", "day", "month", "year")
y <- c("%M", "%H", "%d", "%m", "%Y")
format(df$date, format = y[match(df$fun, x)])
#[1] "51" "09" "05" "01" "2017" "19" "12" "12" "01" "2017"
尽管这给出了警告消息,但输出仍然是正确的。
如果我们在 dplyr
链中需要这个
library(dplyr)
df %>%
mutate(res = format(date, format = y[match(df$fun, x)]))
# date fun res
#1 2017-01-02 22:51:36 minute 51
#2 2017-01-04 09:09:12 hour 09
#3 2017-01-05 19:26:48 day 05
#4 2017-01-07 05:44:24 month 01
#5 2017-01-08 16:02:00 year 2017
#6 2017-01-10 02:19:36 minute 19
#7 2017-01-11 12:37:12 hour 12
#8 2017-01-12 22:54:48 day 12
#9 2017-01-14 09:12:24 month 01
#10 2017-01-15 19:30:00 year 2017
要在此处进行完整的 tidyverse,我们可以使用 purrr 的 invoke_map()
函数。它需要一个函数列表和一个参数值列表列表以用于每个函数。它就像一个向量化的 do.call()
。
df$fun
中的 lubridate 函数需要一个参数 x
,因此我们需要创建一个列表列表,每个日期存储为一个名为 x
的元素。我们可以通过复制日期列并使用 nest()
创建 list-column of data-frames。
df2 <- df %>%
mutate(x = date) %>%
tidyr::nest(x, .key = "params")
df2
#> # A tibble: 10 × 3
#> date fun params
#> <dttm> <chr> <list>
#> 1 2017-01-02 22:51:36 minute <tibble [1 × 1]>
#> 2 2017-01-04 09:09:12 hour <tibble [1 × 1]>
#> 3 2017-01-05 19:26:48 day <tibble [1 × 1]>
#> 4 2017-01-07 05:44:24 month <tibble [1 × 1]>
#> 5 2017-01-08 16:02:00 year <tibble [1 × 1]>
#> 6 2017-01-10 02:19:36 minute <tibble [1 × 1]>
#> 7 2017-01-11 12:37:12 hour <tibble [1 × 1]>
#> 8 2017-01-12 22:54:48 day <tibble [1 × 1]>
#> 9 2017-01-14 09:12:24 month <tibble [1 × 1]>
#> 10 2017-01-15 19:30:00 year <tibble [1 × 1]>
列 params
中的每个元素都是一个 data-frame 和列 x
。这是我们的清单。
df2$params[1]
#> [[1]]
#> # A tibble: 1 × 1
#> x
#> <dttm>
#> 1 2017-01-02 22:51:36
对于我们的两个列表,我们可以使用 invoke_map()
并获得结果列表。
str(purrr::invoke_map(df2$fun, df2$params))
#> List of 10
#> $ : int 51
#> $ : int 9
#> $ : int 5
#> $ : num 1
#> $ : num 2017
#> $ : int 19
#> $ : int 12
#> $ : int 12
#> $ : num 1
#> $ : num 2017
但是因为我们知道这些函数 return 每个只有一个数值,所以我们可以用 invoke_map_dbl()
.
在一个漂亮的向量中得到结果
df2 %>%
mutate(res = purrr::invoke_map_dbl(fun, params)) %>%
select(-params)
#> # A tibble: 10 × 3
#> date fun res
#> <dttm> <chr> <dbl>
#> 1 2017-01-02 22:51:36 minute 51
#> 2 2017-01-04 09:09:12 hour 9
#> 3 2017-01-05 19:26:48 day 5
#> 4 2017-01-07 05:44:24 month 1
#> 5 2017-01-08 16:02:00 year 2017
#> 6 2017-01-10 02:19:36 minute 19
#> 7 2017-01-11 12:37:12 hour 12
#> 8 2017-01-12 22:54:48 day 12
#> 9 2017-01-14 09:12:24 month 1
#> 10 2017-01-15 19:30:00 year 2017
我想使用 dplyr 将名称作为字符串存储在一列中的函数应用于另一列中的值。
我已经使用 mutate_
和 .dots
参数尝试了几件事,但我现在卡住了。
library(lubridate)
library(dplyr)
df <- data.frame(date=as.POSIXct('2017/01/01 12:34') + 1:10*123456,
fun=rep(c('minute','hour','day','month','year'),2))
输入:
> df
date fun
1 2017-01-02 22:51:36 minute
2 2017-01-04 09:09:12 hour
3 2017-01-05 19:26:48 day
4 2017-01-07 05:44:24 month
5 2017-01-08 16:02:00 year
6 2017-01-10 02:19:36 minute
7 2017-01-11 12:37:12 hour
8 2017-01-12 22:54:48 day
9 2017-01-14 09:12:24 month
10 2017-01-15 19:30:00 year
输出:
date fun res
1 2017-01-02 22:51:36 minute 51
2 2017-01-04 09:09:12 hour 9
3 2017-01-05 19:26:48 day 5
4 2017-01-07 05:44:24 month 1
5 2017-01-08 16:02:00 year 2017
6 2017-01-10 02:19:36 minute 19
7 2017-01-11 12:37:12 hour 12
8 2017-01-12 22:54:48 day 12
9 2017-01-14 09:12:24 month 1
10 2017-01-15 19:30:00 year 2017
我们可以使用mapply
df$res <- mapply(function(x,y) get(x)(y), as.character(df$fun), df$date)
df$res
#[1] 51 9 5 1 2017 19 12 12 1 2017
另一种选择是data.table
library(data.table)
setDT(df)[, res := as.integer(get(as.character(fun))(date)), 1:nrow(df)]
df
# date fun res
#1: 2017-01-02 22:51:36 minute 51
#2: 2017-01-04 09:09:12 hour 9
#3: 2017-01-05 19:26:48 day 5
#4: 2017-01-07 05:44:24 month 1
#5: 2017-01-08 16:02:00 year 2017
#6: 2017-01-10 02:19:36 minute 19
#7: 2017-01-11 12:37:12 hour 12
#8: 2017-01-12 22:54:48 day 12
#9: 2017-01-14 09:12:24 month 1
#10: 2017-01-15 19:30:00 year 2017
注意:无需额外努力创建查找表
您可以尝试使用 do.call
,但您必须使用 rowwise
:
library("dplyr")
library("lubridate")
df <- data.frame(
date = as.POSIXct('2017/01/01 12:34') + 1:10*123456,
fun = rep(c('minute','hour','day','month','year'),2),
stringsAsFactors = FALSE
)
df %>% rowwise() %>% mutate(res = as.character(do.call(fun, list(date))))
我能想到的一种方法是使用创建查找 table,然后使用 match
x <- c("minute", "hour", "day", "month", "year")
y <- c("%M", "%H", "%d", "%m", "%Y")
format(df$date, format = y[match(df$fun, x)])
#[1] "51" "09" "05" "01" "2017" "19" "12" "12" "01" "2017"
尽管这给出了警告消息,但输出仍然是正确的。
如果我们在 dplyr
链中需要这个
library(dplyr)
df %>%
mutate(res = format(date, format = y[match(df$fun, x)]))
# date fun res
#1 2017-01-02 22:51:36 minute 51
#2 2017-01-04 09:09:12 hour 09
#3 2017-01-05 19:26:48 day 05
#4 2017-01-07 05:44:24 month 01
#5 2017-01-08 16:02:00 year 2017
#6 2017-01-10 02:19:36 minute 19
#7 2017-01-11 12:37:12 hour 12
#8 2017-01-12 22:54:48 day 12
#9 2017-01-14 09:12:24 month 01
#10 2017-01-15 19:30:00 year 2017
要在此处进行完整的 tidyverse,我们可以使用 purrr 的 invoke_map()
函数。它需要一个函数列表和一个参数值列表列表以用于每个函数。它就像一个向量化的 do.call()
。
df$fun
中的 lubridate 函数需要一个参数 x
,因此我们需要创建一个列表列表,每个日期存储为一个名为 x
的元素。我们可以通过复制日期列并使用 nest()
创建 list-column of data-frames。
df2 <- df %>%
mutate(x = date) %>%
tidyr::nest(x, .key = "params")
df2
#> # A tibble: 10 × 3
#> date fun params
#> <dttm> <chr> <list>
#> 1 2017-01-02 22:51:36 minute <tibble [1 × 1]>
#> 2 2017-01-04 09:09:12 hour <tibble [1 × 1]>
#> 3 2017-01-05 19:26:48 day <tibble [1 × 1]>
#> 4 2017-01-07 05:44:24 month <tibble [1 × 1]>
#> 5 2017-01-08 16:02:00 year <tibble [1 × 1]>
#> 6 2017-01-10 02:19:36 minute <tibble [1 × 1]>
#> 7 2017-01-11 12:37:12 hour <tibble [1 × 1]>
#> 8 2017-01-12 22:54:48 day <tibble [1 × 1]>
#> 9 2017-01-14 09:12:24 month <tibble [1 × 1]>
#> 10 2017-01-15 19:30:00 year <tibble [1 × 1]>
列 params
中的每个元素都是一个 data-frame 和列 x
。这是我们的清单。
df2$params[1]
#> [[1]]
#> # A tibble: 1 × 1
#> x
#> <dttm>
#> 1 2017-01-02 22:51:36
对于我们的两个列表,我们可以使用 invoke_map()
并获得结果列表。
str(purrr::invoke_map(df2$fun, df2$params))
#> List of 10
#> $ : int 51
#> $ : int 9
#> $ : int 5
#> $ : num 1
#> $ : num 2017
#> $ : int 19
#> $ : int 12
#> $ : int 12
#> $ : num 1
#> $ : num 2017
但是因为我们知道这些函数 return 每个只有一个数值,所以我们可以用 invoke_map_dbl()
.
df2 %>%
mutate(res = purrr::invoke_map_dbl(fun, params)) %>%
select(-params)
#> # A tibble: 10 × 3
#> date fun res
#> <dttm> <chr> <dbl>
#> 1 2017-01-02 22:51:36 minute 51
#> 2 2017-01-04 09:09:12 hour 9
#> 3 2017-01-05 19:26:48 day 5
#> 4 2017-01-07 05:44:24 month 1
#> 5 2017-01-08 16:02:00 year 2017
#> 6 2017-01-10 02:19:36 minute 19
#> 7 2017-01-11 12:37:12 hour 12
#> 8 2017-01-12 22:54:48 day 12
#> 9 2017-01-14 09:12:24 month 1
#> 10 2017-01-15 19:30:00 year 2017