簡體   English   中英

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

我想到的一種方法是使用創建查找表,然后使用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

我們可以使用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))))

要在這里完全整理,我們可以使用purrr的invoke_map()函數。 它需要一個函數列表和一個用於每個函數的參數值列表。 它就像一個矢量化的do.call()

df$fun的lubridate函數期望參數x ,因此我們需要創建一個列表列表,每個日期都存儲為名為x的元素。 我們可以通過復制日期列並使用nest()來創建數據框的列表列。

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中的每個元素都是一個帶有列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

但是因為我們知道這些函數每個只返回一個數值,所以我們可以使用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM