【问题标题】:How to switch from funs to list in dplyr when the column name is used?使用列名时如何在 dplyr 中从 funs 切换到 list?
【发布时间】:2019-11-03 11:23:33
【问题描述】:

我尝试将我的代码从 funs()(包 dplyr)切换到 list(),尤其是在 mutate_if () 函数。

不幸的是,我有一段代码使用列名作为输入参数。 但是当使用 list() 函数时,代码会中断!

此示例代码只是将列的内容替换为列名:

library(tibble)
library(dplyr)

atibble=tribble(~A, ~B,
                "A1", "B1",
                "A2", "B2")

print(atibble)

## A tibble: 2 x 2
#  A     B    
#  <chr> <chr>
#1 A1    B1   
#2 A2    B2   

atibble %>% 
  mutate_if(is.character, funs(quo_name(quo(.))))

## A tibble: 2 x 2
#  A     B    
#  <chr> <chr>
#1 A     B    
#2 A     B 

atibble %>% 
  mutate_if(is.character, list(~quo_name(quo(.))))

## A tibble: 2 x 2
#  A     B    
#  <chr> <chr>
#1 .     .    
#2 .     .    

结果不太一样。 :-(

我尝试了很多 quo、enquo、rlang::as_name、.. 的组合,但没有任何帮助。

如何修复 list() 语句,以便代码显示与 funs() 相同的结果?

我的环境:

  • Windows 10
  • R 版本 3.6.1
  • dplyr 版本 0.8.3

谢谢

编辑: tmfmnk 的解决方案有效。我只想在这里展示整个问题。 如果有人找到没有辅助功能的解决方案,我会很高兴看到它。 :-)

library(tibble)
library(dplyr)
library(lubridate)

# my original problem involves dates.
btibble=tribble(~A, ~B,
                ymd("2019-11-04"), ymd("2019-10-20"),
                ymd("2018-02-12"), ymd("2019-02-06"))

# # A tibble: 2 x 2
#   A          B         
#   <date>     <date>    
# 1 2019-11-04 2019-10-20
# 2 2018-02-12 2019-02-06

# And I have a small function that I use.
# It determines the granularity I want for the date column.
getDateUnit <- function(x) {
  if (x == 'A') {
    return ("month")
  }
  return("year")
}

# works fine with funs.
btibble %>%
  mutate_if(is.Date, funs(floor_date(., getDateUnit(quo_name(quo(.))))))

# Column A is on the first of the month, column B is on the first of the year.
# # A tibble: 2 x 2
#   A          B         
#   <date>     <date>    
# 1 2019-11-01 2019-01-01
# 2 2018-02-01 2019-01-01

# does not work with list because the function call is getDateUnit('.').
# every column will be set to first day of year now
btibble %>%
  mutate_if(is.Date, list(~floor_date(., getDateUnit(quo_name(quo(.))))))

# Column A is not formatted by month, but by year.
# # A tibble: 2 x 2
#   A          B         
#   <date>     <date>    
# 1 2019-01-01 2019-01-01
# 2 2018-01-01 2019-01-01

# Throws error
btibble %>%
  mutate_if(is.Date, list(function(x) floor_date(x, getDateUnit(quo_name(enquo(x))))))

# Error: `expr` must quote a symbol, scalar, or call
# Call `rlang::last_error()` to see a backtrace. 

# The workaround I found was using a helper function that 
# does the computing in two steps:
helper_function <- function(x) {
  unit = getDateUnit(quo_name(enquo(x)))
  return(floor_date(x, unit))
}

# with the helper function both snippets below work.
btibble %>%
  mutate_if(is.Date, helper_function)

btibble %>%
  mutate_if(is.Date, list(helper_function))

# # A tibble: 2 x 2
#   A          B         
#   <date>     <date>    
# 1 2019-11-01 2019-01-01
# 2 2018-02-01 2019-01-01

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    函数的list() 内不应有.

    atibble %>%
     mutate_if(is.character, list(function(x) quo_name(enquo(x))))
    
      A     B    
      <chr> <chr>
    1 A     B    
    2 A     B  
    

    【讨论】:

    • 谢谢!您的解决方案适用于我的简化示例。这里有两个注意事项:a). 在列表中通常是可以的,就像这里:atibble %&gt;% mutate_if(is.character, list(~stringr::str_dup(., 2))) 工作正常。 b)它不适用于我原来的问题,但我找到了使用您的解决方案的解决方法。我将编辑我的问题并在那里发布原始问题和我的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 2021-01-07
    • 2016-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多