【问题标题】:embracing operator inside mutate function在 mutate 函数中包含运算符
【发布时间】:2021-07-12 12:17:50
【问题描述】:

我正在尝试编写一个我经常在我的论文中使用但很难让它运行的函数。

我认为,代码可以运行,但是一旦我运行该函数就会失败,因为 R 如何通过包含函数选项读取指定的变量。这是一个变量 prburden 和 link to sample data 的成功代码:

 rburden_data2 %>%
  
  # select only percent rent burden vars
  select(tractid, year, CBSA_name, contains("prburden")) %>%
  
  # group by tractid and count # of tracts by group 
  group_by(tractid) %>% 
  
  # create rent burden change indicator - continuous
  mutate(cont_chg_prburden = prburden[year == "2019"] - prburden[year == "2000"] ) %>%
  
  # create rent burden change indicator - categorical
  mutate(cat_chg_prburden = case_when(cont_chg_prburden   < 0 ~ "negative",
                                      cont_chg_prburden  == 0 ~ "zero",
                                      cont_chg_prburden   > 0  ~ "positive" ,
                                      TRUE ~ "NA")) %>%
  
  
  # create rent burden change indicator - binary
  mutate(bi_chg_prburden = case_when(cat_chg_prburden == "negative" ~ "loss",
                                     cat_chg_prburden == "positive" ~ "gain",
                                     TRUE ~ "NA")) %>%
  glimpse()

在这个命令中我:

  • 获取我的数据集 (rburden_data2)
  • 仅包含重要变量的子集
  • 按人口普查区 (tractid) 分组
  • 创建第一年和去年租金负担之间差异的连续指标
  • 创建负、零和正变化的分类指标
  • 创建研究期间收益或损失的二进制指标

这是我尝试运行的函数,我指定了相同的变量 prburden:

# function  ++++++++++++++++++++
change_indicators <- function(data, var){
  
  data %>%
    
    # select only percent rent burden vars
    select(tractid, year, contains("prburden")) %>%
    
    # group by tractid and count # of tracts by group 
    group_by(tractid) %>% 
    
    # create rent burden change indicator - continuous
    mutate("cont_chg_{{ var }} ":= "{{var}}"[year == 2019] - "{{var}}"[year == 2000]) %>%
    
    # create rent burden change indicator - categorical
    mutate("cat_chg_{{ var }}" := case_when("cont_chg_{{ var }}"    < 0 ~ "negative",
                                             "cont_chg_{{ var }}"   == 0 ~ "zero",
                                             "cont_chg_{{ var }}"    > 0  ~ "positive" ,
                                             TRUE ~ "NA")) %>%
    
    
    # create rent burden change indicator - binary
    mutate("bi_chg_{{ var }}" := case_when("cat_chg_{{ var }}" == "negative" ~ "loss",
                                           "cat_chg_{{ var }}" == "positive" ~ "gain",
                                           TRUE ~ "NA")) %>%
    
    
    
    glimpse() 
  
}

# test ++++++++++++++++++++
test <-  change_indicators(data = rburden_data2, 
                           var = prburden)  

# error ++++++++++++++++++++
Error: Problem with `mutate()` column `cont_chg_prburden `.
ℹ `cont_chg_prburden  = "{{var}}"[year == 2019] - "{{var}}"[year == 2000]`.
x non-numeric argument to binary operator
ℹ The error occurred in group 1: tractid = "01001020100".

我遇到的问题是,当我通过所有名称更改传递变量“prburden”,然后调用它来计算年份差异时。我对如何使用 {{}} 运算符很困惑,因为我认为在第一个 := 之后我不需要“”,但它会引发错误。

任何将我的第一个代码块转换为可执行函数的帮助将不胜感激。谢谢!

【问题讨论】:

  • 谢谢,@RonakShah。我已经包含了一个示例数据集并对问题进行了一些重新格式化。

标签: r operators tidyverse dplyr


【解决方案1】:

试试这个功能-

library(dplyr)

change_indicators <- function(data, var){
  val <- deparse(substitute(var))
  col1 <- paste0('cont_chg_', val)
  col2 <- paste0('cat_chg_', val)
  col3 <- paste0('bi_chg_', val)
  
  data %>%
    # select only percent rent burden vars
    select(tractid, year, contains("prburden")) %>%
    # group by tractid and count # of tracts by group 
    group_by(tractid) %>% 
    # create rent burden change indicator - continuous
    mutate(!! col1 := {{var}}[year == 2019] - {{var}}[year == 2000],
           !! col2  := case_when(.data[[col1]]    < 0 ~ "negative",
                                .data[[col1]]   == 0 ~ "zero",
                                .data[[col1]]    > 0  ~ "positive" ,
                                TRUE ~ NA_character_), 
           !!col3 := case_when(.data[[col2]] == "negative" ~ "loss",
                                .data[[col2]] == "positive" ~ "gain",
                                TRUE ~ NA_character_)) %>%
    glimpse() 
  
}
  • 直接使用列名时使用{{var}}
  • 我不确定"cont_chg_{{ var }}" 是否有效,我更喜欢在那里使用.data 代词。
  • 要分配列名,请使用!!name := 创建新列。
  • 将“NA”替换为NA_character_
  • 将所有内容整合到一个 mutate 呼叫中。
data %>%
  ungroup %>%
  change_indicators(prburden)

#Rows: 219,246
#Columns: 10
#Groups: tractid [73,082]
#$ tractid           <chr> "01001020100", "01001020100", "01001020100"…
#$ year              <chr> "2000", "2013", "2019", "2000", "2013", "20…
#$ prburden_no       <dbl> 60.73620, 67.88991, 44.64286, 46.07843, 42.…
#$ prburden          <dbl> 14.110429, 13.761468, 35.119048, 16.666667,…
#$ prburden_sev      <dbl> 17.177914, 18.348624, 18.452381, 26.470588,…
#$ prburden_not      <dbl> 7.975460, 0.000000, 1.785714, 10.784314, 10…
#$ prburden_all      <dbl> 31.28834, 32.11009, 53.57143, 43.13725, 46.…
#$ cont_chg_prburden <dbl> 21.008618, 21.008618, 21.008618, 7.457847, …
#$ cat_chg_prburden  <chr> "positive", "positive", "positive", "positi…
#$ bi_chg_prburden   <chr> "gain", "gain", "gain", "gain", "gain", "ga…

【讨论】:

  • 太好了,谢谢 Ronak,这完全奏效了。我也很沮丧,因为我没有经常看到“cont_chg_{{ var }}”在野外工作。
  • 接下来的问题是如何能够让函数为多个变量运行。我试过:vars &lt;- c("prburden", "prburden_sev", "prburden_all") mytest &lt;- map_df(vars, change_indicators(data = rburden_data, var = vars)),但它一直抛出错误:`x non-numeric argument to binary operator. I can't figure out how to get the function to read the var names in the vector as var names and not characters. I tried the deparse(substitute(var))` 无济于事。
  • 对于多个变量,我认为您应该将它们用作字符变量。没有简单的方法将它们视为不带引号的变量。
  • 请原谅我的无知,但我该怎么做呢?我认为问题在于它把它们当作字符来阅读,而不需要它们。
  • 实际上,这需要完全改变答案。此外,您需要将变量作为字符串 change_indicators("prburden") 传递,而不是将函数调用为 change_indicators(prburden) 。您能否提出一个新问题,以便我们可以将这两种方法分开?
【解决方案2】:

我发现最简单的方法是先定义新变量,将它们转换为符号,然后包含结果变量,如下所示:

  change_indicators <- function(data, var){
  #create new variable names first, and use the rlang::sym() function to convert from string to symbol
  var_new <- sym(var)
  cont_var <- sym(paste0("cont_chg_", var))
  cat_var <- sym(paste0("cat_chg_", var))
  bi_var <- sym(paste0("bi_chg_", var))
  
  data %>%
    
    # select only percent rent burden vars
    select(tractid, year, contains("prburden")) %>%
    
    # group by tractid and count # of tracts by group 
    group_by(tractid) %>% 
    
    # create rent burden change indicator - continuous
    mutate({{cont_var}}:= {{var_new}}[year == 2019] - {{var_new}}[year == 2000]) %>%
    
    # create rent burden change indicator - categorical
    mutate({{cat_var}} := case_when({{cont_var}} < 0 ~ "negative",
                                            {{cont_var}} == 0 ~ "zero",
                                            {{cont_var}} > 0  ~ "positive" ,
                                            TRUE ~ "NA")) %>%
    # create rent burden change indicator - binary
    mutate({{bi_var}} := case_when({{cat_var}} == "negative" ~ "loss",
                                           {{cat_var}} == "positive" ~ "gain",
                                           TRUE ~ "NA")) %>%
    
    
    
    glimpse() 
  
}

这是我在你的数据上运行它时的输出,在首先取消组合 df 之后:

rburden_data2 <- read_rds("data/rburden_data2.rds") %>% 
  ungroup()

# use a quote here, because in previous comments you loop through a vector
test <-  change_indicators(data = rburden_data2, 
                           var = "prburden")  

Rows: 219,246
Columns: 10
Groups: tractid [73,082]
$ tractid           <chr> "01001020100", "01001020100", "01001020100", "01001020200", "…
$ year              <chr> "2000", "2013", "2019", "2000", "2013", "2019", "2000", "2013…
$ prburden_no       <dbl> 60.73620, 67.88991, 44.64286, 46.07843, 42.90429, 33.85214, 6…
$ prburden          <dbl> 14.110429, 13.761468, 35.119048, 16.666667, 3.300330, 24.1245…
$ prburden_sev      <dbl> 17.177914, 18.348624, 18.452381, 26.470588, 43.564356, 38.521…
$ prburden_not      <dbl> 7.975460, 0.000000, 1.785714, 10.784314, 10.231023, 3.501946,…
$ prburden_all      <dbl> 31.28834, 32.11009, 53.57143, 43.13725, 46.86469, 62.64591, 2…
$ cont_chg_prburden <dbl> 21.0086182, 21.0086182, 21.0086182, 7.4578470, 7.4578470, 7.4…
$ cat_chg_prburden  <chr> "positive", "positive", "positive", "positive", "positive", "…
$ bi_chg_prburden   <chr> "gain", "gain", "gain", "gain", "gain", "gain", "gain", "gain…

这避免了尝试在其他函数(如 case_when)中转换为符号的问题,这可能会让人头疼。

【讨论】:

  • 谢谢,康纳。这也有效。我的下一个后续问题是如何让这个函数运行多个变量。 vars &lt;- c("prburden", "prburden_sev", "prburden_all") mytest &lt;- map_df(vars, get_change_connor(data = rburden_data, var = vars)) 似乎不起作用
猜你喜欢
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 2021-02-28
  • 2020-10-28
  • 2010-11-01
  • 2017-02-05
相关资源
最近更新 更多