r-在dplyr中的特定列范围中使用mutate case_when()



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

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

创建于2022-03-12由reprex包(v2.0.1(

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

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    

请使用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

创建于2022-03-12由reprex包(v2.0.1(

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    

使用rowwise方法的另一种选择是对TRUE值求和,这种方法在处理较大的数据集时可能会非常昂贵。

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

最新更新