在 dplyr 的特定列范围内使用 mutate case_when()

Use mutate case_when() in a specific range of columns in dplyr

我有一个看起来像 df1 的大数据框。 如果任何字符包含字符串 S,我想在 col2:col4 (col2,col3,col4) 之间的列范围内搜索。

library(tidyverse)

df <- tibble(position=c(100,200,300),
             correction=c("62M89S", 
                          "8M1D55M88S",
                          "1S25M1S36M89S"))

df1 <- df %>% 
  separate(correction, into = str_c("col", 1:5), 
           sep = "(?<=\D)(?=\d)", fill = "left", remove = FALSE)

df1
#> # A tibble: 3 × 7
#>   position correction    col1  col2  col3  col4  col5 
#>      <dbl> <chr>         <chr> <chr> <chr> <chr> <chr>
#> 1      100 62M89S        <NA>  <NA>  <NA>  62M   89S  
#> 2      200 8M1D55M88S    <NA>  8M    1D    55M   88S  
#> 3      300 1S25M1S36M89S 1S    25M   1S    36M   89S

reprex package (v2.0.1)

创建于 2022-03-12

我希望我的数据看起来像这样

df1
#>   position correction    col1  col2  col3  col4  col5     inner_S
#>      <dbl> <chr>         <chr> <chr> <chr> <chr> <chr>      
#> 1      100 62M89S        <NA>  <NA>  <NA>  62M   89S         NO 
#> 2      200 8M1D55M88S    <NA>  8M    1D    55M   88S         NO
#> 3      300 1S25M1S36M89S 1S    25M   1S    36M   89S         YES

因为在col3.

中有字符1S

我试过了,但我确定我违反了一些属性

df1 %>% 
  mutate_at(vars(col2:col4),
                             ~inner_S=case_when(grepl("S",.) ~ "Yes", 
                              TRUE ~ "No"
                            ))

dplyrc_across 对于这样的操作非常方便:

df1 %>% 
  rowwise() %>% 
  mutate(inner_S = ifelse(any(grepl('S', c_across(col1:col4))), 'YES', 'NO'))

  position correction    col1  col2  col3  col4  col5  inner_S
     <dbl> <chr>         <chr> <chr> <chr> <chr> <chr> <chr>  
1      100 62M89S        NA    NA    NA    62M   89S   NO     
2      200 8M1D55M88S    NA    8M    1D    55M   88S   NO     
3      300 1S25M1S36M89S 1S    25M   1S    36M   89S   YES    

jdobres 的回答很完美。这是一个更复杂的使用 across:

library(tidyverse)

df1 %>% 
  mutate(across(col1:col4, ~ifelse(
    str_detect(., 'S'), TRUE, FALSE), .names = 'new_{col}')) %>% 
  unite(inner_S, starts_with('new'), na.rm = TRUE, sep = ' ') %>% 
  mutate(inner_S = ifelse(str_detect(inner_S, 'TRUE'), "YES", "NO"))
  position correction    col1  col2  col3  col4  col5  inner_S
     <dbl> <chr>         <chr> <chr> <chr> <chr> <chr> <chr>  
1      100 62M89S        NA    NA    NA    62M   89S   NO     
2      200 8M1D55M88S    NA    8M    1D    55M   88S   NO     
3      300 1S25M1S36M89S 1S    25M   1S    36M   89S   YES    

请使用 data.table

找到另一个可能的解决方案

Reprex

  • 代码
library(data.table)

setDT(df1)[, inner_S := apply(.SD, 1, function(x) fifelse(any(grepl("S", x)), "YES", "NO")), .SDcols = paste0("col", 2:4)][]
  • 输出
#>    position    correction col1 col2 col3 col4 col5 inner_S
#> 1:      100        62M89S <NA> <NA> <NA>  62M  89S      NO
#> 2:      200    8M1D55M88S <NA>   8M   1D  55M  88S      NO
#> 3:      300 1S25M1S36M89S   1S  25M   1S  36M  89S     YES

reprex package (v2.0.1)

于 2022 年 3 月 12 日创建

使用 rowwise 方法的替代方法(在处理较大的数据集时可能会非常昂贵)是对 TRUE 值求和。

df1 %>%
      mutate(inner_S = ifelse(rowSums(across(col1:col4, str_detect, "S"), na.rm = T) > 1, "YES", "NO"))