【问题标题】:R mutate multiple columns with ifelseR用ifelse改变多列
【发布时间】:2020-07-23 06:38:18
【问题描述】:

这是与此 (R Mutate multiple columns with ifelse()-condition) 类似的问题,但我无法将其应用于我的问题。

这是一个可重现的例子:

df <- structure(list(comm_id = c("060015", "060015", "060015", "060015", 
"060015", "060015", "060015", "060015", "060015", "060015", "060015"
), trans_year = c(1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 
2000, 2001, 2002), f10_1 = c(1996, 1996, 1996, 1996, 1996, 1996, 
1996, 1996, 1996, 1996, 1996), f10_2 = c(1997, 1997, 1997, 1997, 
1997, 1997, 1997, 1997, 1997, 1997, 1997)), row.names = c(NA, 
-11L), class = c("tbl_df", "tbl", "data.frame"))

我想使用ifelse 条件创建额外的列(在我的实际问题中,以类似的方式超过 10 列),这可以用蛮力完成,如下所示。但我的实际问题有 10 多个这样的列,因此它会从更优雅的方法中受益匪浅。

df %>%
  mutate(post_f10_1 = ifelse(trans_year >= f10_1 & trans_year < f10_1 +5, 1, 0),
         post_f10_2 = ifelse(trans_year >= f10_2 & trans_year < f10_2 +5, 1, 0))

我尝试了以下几种不同的失败方法:

base,

n <- c(1:2)
df[paste0("post_f10_", n)] <- lapply(n, function(x) 
  ifelse(df$trans_year >= paste0("f10_", x) & df$trans_year < paste0("f10_", x) + 5, 1, 0))
#  Error in paste0("f10_", x) + 5 : non-numeric argument to binary operator 

带有来自tidyverse的新across函数

df %>%
  mutate(across(starts_with("f10_"), 
                ~ ifelse(trnas_year >= .x & trans_year < .x + 5, 1, 0), .names = "post_{col}"))
# Error: Problem with `mutate()` input `..1`.
# x object 'trnas_year' not found
# ℹ Input `..1` is `across(...)`.

我想要的输出看起来像

  comm_id trans_year f10_1 f10_2 post_f10_1 post_f10_2
   <chr>        <dbl> <dbl> <dbl>      <dbl>      <dbl>
 1 060015        1992  1996  1997          0          0
 2 060015        1993  1996  1997          0          0
 3 060015        1994  1996  1997          0          0
 4 060015        1995  1996  1997          0          0
 5 060015        1996  1996  1997          1          0
 6 060015        1997  1996  1997          1          1
 7 060015        1998  1996  1997          1          1
 8 060015        1999  1996  1997          1          1
 9 060015        2000  1996  1997          1          1
10 060015        2001  1996  1997          0          1
11 060015        2002  1996  1997          0          0

如果可能,我更喜欢tidyverse 方法。谢谢!

更新

我原来的tidyverse 方法由于拼写错误而不起作用。所以我更新了OP。另外,下面的答案比我在这里发布的要优雅得多。

df %>%
+   mutate(across(starts_with("f10_"), 
+                 ~ ifelse(trans_year >= .x & trans_year < .x + 5, 1, 0), .names = "post_{col}"))
# A tibble: 11 x 6
   comm_id trans_year f10_1 f10_2 post_f10_1 post_f10_2
   <chr>        <dbl> <dbl> <dbl>      <dbl>      <dbl>
 1 060015        1992  1996  1997          0          0
 2 060015        1993  1996  1997          0          0
 3 060015        1994  1996  1997          0          0
 4 060015        1995  1996  1997          0          0
 5 060015        1996  1996  1997          1          0
 6 060015        1997  1996  1997          1          1
 7 060015        1998  1996  1997          1          1
 8 060015        1999  1996  1997          1          1
 9 060015        2000  1996  1997          1          1
10 060015        2001  1996  1997          0          1
11 060015        2002  1996  1997          0          0

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    你可以使用:

    library(dplyr)
    
    df %>%  
         mutate(across(starts_with("f10_"), 
                   ~as.integer(trans_year >= . & trans_year < (. + 5)), 
                   .names = 'post_{col}'))
    
    
    #  comm_id trans_year f10_1 f10_2 post_f10_1 post_f10_2
    #   <chr>        <dbl> <dbl> <dbl>      <int>      <int>
    # 1 060015        1992  1996  1997          0          0
    # 2 060015        1993  1996  1997          0          0
    # 3 060015        1994  1996  1997          0          0
    # 4 060015        1995  1996  1997          0          0
    # 5 060015        1996  1996  1997          1          0
    # 6 060015        1997  1996  1997          1          1
    # 7 060015        1998  1996  1997          1          1
    # 8 060015        1999  1996  1997          1          1
    # 9 060015        2000  1996  1997          1          1
    #10 060015        2001  1996  1997          0          1
    #11 060015        2002  1996  1997          0          0
    

    或者在基础 R 中使用 lapply

    cols <- paste0('f10_', 1:2)
    
    df[paste0('post_', cols)] <- lapply(df[cols], function(x) 
              as.integer(df$trans_year >= x & df$trans_year < (x + 5)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-27
      相关资源
      最近更新 更多