【问题标题】:How to shorten this long dplyr syntax?如何缩短这个长的 dplyr 语法?
【发布时间】:2021-12-10 17:19:31
【问题描述】:

在 tibble 中,我希望能够更正变量 nbeta_dep01nbeta_dep02 所采用的某些值 ...

下面是我正在做的一个可重现的例子。

我想知道是否有办法缩短语法(因为在我的示例中,我复制并粘贴了与变量 nbeta_depXX 一样多次的更正指令)

suppressMessages(library(dplyr))

test <- tribble(
  ~ent, ~dep_impl, ~nbeta_dep01, ~nbeta_dep02, ~nbeta_dep03, ~nbeta_dep04, ~nbeta_dep05,
  "a",  "01",  0,   0,   0,   0,   0,  
  "b",  "03",  2,   0,   3,   0,   1,
  "c",  "05",  0,   0,   0,   1,   0,
  "d",  "02",  0,   0,   0,   0,   0
)

test %>% 
  rowwise() %>% 
  mutate(
    nbeta_dep01 = ifelse(
      nbeta_dep01==0 & nbeta_dep02==0 & nbeta_dep03==0 & nbeta_dep04==0 & nbeta_dep05==0 & dep_impl=="01",
      1,
      nbeta_dep01),
    nbeta_dep02 = ifelse(
      nbeta_dep01==0 & nbeta_dep02==0 & nbeta_dep03==0 & nbeta_dep04==0 & nbeta_dep05==0 & dep_impl=="02",
      1,
      nbeta_dep02),
    nbeta_dep03 = ifelse(
      nbeta_dep01==0 & nbeta_dep02==0 & nbeta_dep03==0 & nbeta_dep04==0 & nbeta_dep05==0 & dep_impl=="03",
      1,
      nbeta_dep03),
    nbeta_dep04 = ifelse(
      nbeta_dep04==0 & nbeta_dep02==0 & nbeta_dep03==0 & nbeta_dep04==0 & nbeta_dep05==0 & dep_impl=="04",
      1,
      nbeta_dep04),
  )
#> # A tibble: 4 x 7
#> # Rowwise: 
#>   ent   dep_impl nbeta_dep01 nbeta_dep02 nbeta_dep03 nbeta_dep04 nbeta_dep05
#>   <chr> <chr>          <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
#> 1 a     01                 1           0           0           0           0
#> 2 b     03                 2           0           3           0           1
#> 3 c     05                 0           0           0           1           0
#> 4 d     02                 0           1           0           0           0
Created on 2021-10-25 by the reprex package (v2.0.1)

【问题讨论】:

  • 我没有检查逻辑是否通常可以简化,但您可能想要检查case_when,而不是多个 ifelse 命令。

标签: r dplyr purrr


【解决方案1】:

你可以使用

library(dplyr)
library(stringr)

test %>% 
  mutate(across(matches("dep\\d+$"), 
       ~ifelse(rowSums(across(nbeta_dep01:nbeta_dep05)) == 0 & dep_impl == str_extract(cur_column(), "\\d+$"),
               1,
               .x)))

返回

# A tibble: 4 x 7
  ent   dep_impl nbeta_dep01 nbeta_dep02 nbeta_dep03 nbeta_dep04 nbeta_dep05
  <chr> <chr>          <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
1 a     01                 1           0           0           0           0
2 b     03                 2           0           3           0           1
3 c     05                 0           0           0           1           0
4 d     02                 0           1           0           0           0
  • 我们使用正则表达式标识要更改的列:"dep\\d+$" 匹配所有以“dep”结尾且后跟两位数字的列。这些列在 across() 函数中使用。
  • if 语句被简化:因为所有nbeta_dep 列都需要为0,我们通过使用rowSum 函数和选择across() 函数来获取这些列的总和。此外,我们检查当前列名中的数字是否与列 dep_impl 中的数字匹配。
  • 如果满足这些条件,我们返回1,否则返回当前列/行中已有的值.x

【讨论】:

  • 太棒了,我不会正则表达式!
【解决方案2】:

您可以使用函数starts_with 引用名称以相同方式开头的列:

test %>% 
  mutate(across(starts_with("nbeta"),
         ~ifelse(
      nbeta_dep01==0 & nbeta_dep02==0 & nbeta_dep03==0 & nbeta_dep04==0 & nbeta_dep05==0 & dep_impl=="01",
      1,
      nbeta_dep01)))

【讨论】:

  • 谢谢,但缺少最后一个条件“dep_impl == XX”
【解决方案3】:

它也可以在rowwise 下工作,并且没有matches()rowSums()

test %>% 
rowwise %>% 
mutate(across(3:7, ~ifelse(grepl(dep_impl, cur_column()) && sum(across(3:7)) == 0, 1, .)))
# A tibble: 4 x 7
# Rowwise: 
  ent   dep_impl nbeta_dep01 nbeta_dep02 nbeta_dep03 nbeta_dep04 nbeta_dep05
  <chr> <chr>          <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
1 a     01                 1           0           0           0           0
2 b     03                 2           0           3           0           1
3 c     05                 0           0           0           1           0
4 d     02                 0           1           0           0           0

【讨论】:

  • 好的,非常感谢!
猜你喜欢
  • 2013-05-25
  • 1970-01-01
  • 2020-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多