【问题标题】:R dplyr::mutate_ and lubridate::parse_date_time Standard Evaluation not working together as expectedR dplyr::mutate_ 和 lubridate::parse_date_time 标准评估未按预期协同工作
【发布时间】:2016-03-11 03:45:00
【问题描述】:

我认为这是 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_ 一起工作?

【问题讨论】:

    标签: r dplyr lubridate


    【解决方案1】:

    你试过了吗

    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)))
    

    【讨论】:

    • 这不起作用,因为我试图以编程方式使用它,目标是使用一个变量(varname),它包含一个字符串(“start_date”),它是数据框df中的一列。无论如何,使用 NSE 版本不是更容易吗?还是您的意思是在上面的代码块中使用 var_name 而不是 start_date?
    • @Manny 不,我的意思是使用 start_date。这样做可以让您使用标准方法构建公式。
    • @alisare 对不起,我没有看到你更新了你的答案 Hong ooi。我认为总体上最干净和最快的解决方案可能是在管道之外进行。感谢您提供解决方案和建议。我认为 Hong Ooi 在技术上是我想要的。
    【解决方案2】:

    标准评估评估事物(或多或少)就像它们在基础 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 选项打开了一些编程可能性,但以方便为代价(加上大量的混乱)。

    【讨论】:

    • 感谢这有助于我理解潜在问题。如果这是真的,我有几个后续问题:... 而不是单列 tbl_df,它 parse_date_time 无法处理。 为什么 NSE 版本仍然正确返回,这不也是tbl_df?另外,哪种解决方法是最有效的解决方法?
    • 当您向 NSE 版本传递一个不带引号的列名时,它会在内部子集到该列中值的向量。 dplyr 在返回 tbl_dftbl_dt 数据帧和获取类似数据帧的对象方面是一致的,但在内部它使用向量来处理单个变量,因为这就是其他一切使用的方式。
    • 至于什么是最有效的,除非你运行这个代码的数千次迭代或者你的数据是巨大的,否则速度可能不是问题,所以选择你看时仍然有意义的那个在 6 个月左右的时间内完成。如果速度真的很重要,那么使用tbl_df 可能是最快的,因为您可以避免转化,但您必须进行基准测试才能看到。
    • 如果你将它插入到一个相当长的管道中,这可能会爆炸,因为它将使用dfdforiginal 值,而不是已经处理过的值管道。
    • @HongOoi 是的。你知道是否有办法在 SE 中引用创建的变量(除了将代码编写为字符串)?实际上,这是我长期以来一直存在的问题。
    猜你喜欢
    • 1970-01-01
    • 2014-12-24
    • 2019-05-07
    • 1970-01-01
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多