R dplyr :: mutate_和lubridate :: parse_date_time标准评估未按预期方式一起工作

时间:2016-03-11 03:45:00

标签: r dplyr lubridate

我认为这是dplyr中的一个错误,但它可能只是我自己对标准评估的误解。如果有人可以提供帮助那就太棒了

考虑:

library(dplyr)
library(lubridate)

df <- frame_data( ~ start_date,
                    "07/15/2015 15:39", 
                    "07/15/2015 15:42")

df_NSE <- df %>% 
          mutate(response_date = parse_date_time(start_date, orders ="mdY hm"))

我原以为像以下这样的东西会成为标准评估的等价物:

  var_name <- "start_date"

    df_SE_expected_to_work <- df %>% 
              mutate_(response_date = ~parse_date_time(var_name, orders ="mdY hm"))

但是这只是抛出一个警告,并且只有response_date列的空白行:

Warning message:
All formats failed to parse. No formats found. 

我尝试了很多变种,即使是使用interp,只是为了确保它不是我对NSE的理解,例如:

df_SE_interp_expected_to_work <- df %>% 
          mutate_(response_date = interp(~parse_date_time(var_name, orders ="mdY hm"), var_name = var_name))

但我得到了同样的结果

我能够为这两种情况破解一个有效的解决方案:

df_SE_working <- df %>% 
          mutate_(response_date = ~parse_date_time(df[[var_name]], orders ="mdY hm"))
df_SE_interp_working <- df %>% 
          mutate_(response_date = interp(~parse_date_time(df[[var_name]], orders ="mdY hm"), var_name = var_name))
sessionInfo()
R version 3.2.3 (2015-12-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 14.04.4 LTS

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8    LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] lazyeval_0.1.10.9000 lubridate_1.5.0      ednaetl_0.1          purrr_0.2.0          psqlfun_0.1         
 [6] dplyr_0.4.3.9000     tidyr_0.4.0          uuid_0.1-2           RPostgreSQL_0.4      DBI_0.3.1           

loaded via a namespace (and not attached):
 [1] Rcpp_0.12.3        assertthat_0.1     R6_2.1.2           magrittr_1.5       stringi_1.0-1     
 [6] tools_3.2.3        stringr_1.0.0      yaml_2.1.13        parallel_3.2.3     rsconnect_0.4.1.11
[11] knitr_1.12.3     

也许我只是错过了一些明显可以使用mutate_的东西?

2 个答案:

答案 0 :(得分:0)

你试过吗

df2 <- df %>%
    mutate_(response_date = ~parse_date_time(start_date, orders ="mdY hm"))

使用公式表示法只是为了避免R试图评估给定的表达式。因此,您可以使用与NSE中完全相同的调用,但需要添加一个波形。

为了说明如何以编程方式执行此操作:

x <- "start_date"
df2 <- df %>%
    mutate_(response_date = formula(sprintf("~parse_date_time(%s, orders='mdY hm')", x)))

答案 1 :(得分:0)

标准评估评估事物(或多或少),就像它们在基数R中一样,这意味着如果要将var_name评估为列名,则不能使用未加引号的列名;相反,你必须指定一个想要子集的data.frame。

此处还有另一个问题:当您对列名称进行子集时,tbl_df不返回向量,而是tbl_dfparse_date_time无法处理。

例如,

> df[,var_name]
Source: local data frame [2 x 1]

        start_date
             (chr)
1 07/15/2015 15:39
2 07/15/2015 15:42

> dfdf <- as.data.frame(df)
> dfdf[,var_name]
[1] "07/15/2015 15:39" "07/15/2015 15:42"

这可能是dplyr努力使一切的结果,它会返回一个数据帧。因此

df %>% mutate_(response_date = ~parse_date_time(df[,var_name], orders ="mdY hm"))

会失败,但

dfdf <- as.data.frame(df)
dfdf %>% mutate_(response_date = ~parse_date_time(dfdf[,var_name], orders ="mdY hm"))

会奏效。您可以使用[[子集来完成上述工作,这会为tbl_dfdata.frame返回一个向量;另一种选择是用unlist强制解决问题。

据我所知,没有办法调用链中创建的列或分组列(除了嵌套分组);总体而言,SE选项打开了一些编程可能性,但代价是方便(加上大量的混淆)。