【问题标题】:String matching over multiple columns with specific string names在具有特定字符串名称的多个列上进行字符串匹配
【发布时间】:2021-12-05 02:16:39
【问题描述】:

我有兴趣对一组列进行字符串检测。如果找到该字符串(在本例中为ZSD),我想返回列号/名称。如果找到多个匹配项,我想用该字符串返回最后一个列名/编号。

输入

我的输入是这样的:

a.zsd                b.zsd   c.zsd   d.zsd
'ZSD'                'ZAD'   NA      'ZAD'
'ZAD'                NA      NA      'ZSD'
NA                   NA      'ZAD'   NA
'Not Achieved ZSD'   NA      'ZAD'   NA
'ZSD'                'ZSD'   NA      'ZSD'
NA                   NA      NA      NA

输出

我需要的输出是一个新列zsd.level

a.zsd                b.zsd   c.zsd   d.zsd zsd.level
'ZSD'                'ZAD'   NA      'ZAD'    a
'ZAD'                NA      NA      'ZSD'    d
NA                   NA      'ZAD'   NA       NA
'Not Achieved ZSD'   NA      'ZAD'   NA       a
'ZSD'                'ZSD'   NA      'ZSD'    d
NA                   NA      NA      NA       NA

信息:

我的数据框有一百多列。我只对名称以字符串.zsd 结尾的某些列感兴趣。这些列可以具有NA 或以下字符串值之一ZADZSDNot Achieved ZSD

我只是对检测字符串ZSD 的存在感兴趣。如果在任何列中都找不到,它应该在输出列中返回 NA (zsd.level)。如果在多列中找到该字符串,我想返回包含该字符串的最后一列名称/编号。

我的问题与这篇文章类似但不完全相同dplyr filter with condition on multiple columns

输入

dput(df)

structure(list(a.zsd = c("ZSD", "ZAD", NA, "Not Achieved ZSD", "ZSD", NA), 
               b.zsd = c("ZAD", NA, NA, NA, "ZSD", NA), 
               c.zsd = c(NA, NA, "ZAD", "ZAD", NA, NA), 
               d.zsd = c("ZAD", "ZSD", NA, NA, "ZSD", NA)), 
               class = "data.frame", row.names = c(NA, -6L))

部分解决方案

要选择名称以.zsd 结尾的那些列,我可以这样做

library(stringr)
library(tidyverse)

df %>%
  select(ends_with(".zsd"))

要选择或过滤带有字符串ZSD 的行,我可以这样做

str_detect(., "ZSD"))

但是我怎样才能把多个条件放在一起呢?任何帮助将不胜感激。

【问题讨论】:

  • 如果ZSD 是像第 5 行那样的多列怎么办
  • "如果找到多个匹配项,我想返回包含该字符串的最后一列。"
  • 对不起,这是一个字符串。我应该更新并澄清它只是在一列中。

标签: r string dplyr


【解决方案1】:

另一种选择,但比亲爱的 TarJae 的要复杂一点:

library(dplyr)
library(tidyr)
library(stringr)

df %>% 
  mutate(rn = row_number()) %>% 
  pivot_longer(-rn) %>% 
  group_by(rn) %>% 
  filter(str_detect(value, "ZSD")) %>% 
  slice_tail() %>% 
  summarise(name = str_remove(name, ".zsd")) %>% 
  right_join(df %>% mutate(rn = row_number()), by = "rn") %>%
  arrange(rn) %>% 
  ungroup() %>% 
  select(ends_with("zsd"), zsd.level = name)

返回

# A tibble: 6 x 5
  a.zsd            b.zsd c.zsd d.zsd zsd.level
  <chr>            <chr> <chr> <chr> <chr>    
1 ZSD              ZAD   NA    ZAD   a        
2 ZAD              NA    NA    ZSD   d        
3 NA               NA    ZAD   NA    NA       
4 Not Achieved ZSD NA    ZAD   NA    a        
5 ZSD              ZSD   NA    ZSD   d        
6 NA               NA    NA    NA    NA 

【讨论】:

  • 不错的解决方案。我喜欢它。
  • @Martin Gal,请你看看下面的帖子 stackoverflow.com/questions/69609589/…>
  • 感谢您的解决方案,但是它不适用于原始数据。
【解决方案2】:

我们可以这样做:

library(dplyr)
library(tidyr)
library(stringr)

df %>%  
  mutate(across(contains("zsd"), ~case_when(str_detect(., "ZSD") ~ cur_column()), .names = 'new_{col}')) %>%
  unite(zsd_level, starts_with('new'), na.rm = TRUE, sep = ' ') %>% 
  mutate(zsd_level = str_remove_all(zsd_level, ".zsd"),
         zsd_level = str_sub(zsd_level, -1))

输出:

 a.zsd b.zsd c.zsd d.zsd zsd_level
1              ZSD   ZAD  <NA>   ZAD         a
2              ZAD  <NA>  <NA>   ZSD         d
3             <NA>  <NA>   ZAD  <NA>          
4 Not Achieved ZSD  <NA>   ZAD  <NA>         a
5              ZSD   ZSD  <NA>   ZSD         d
6             <NA>  <NA>  <NA>  <NA>          

【讨论】:

  • 查看我的更新。现在应该够用了!
  • 太好了,它大部分都在工作。当字符串丢失时,我可以改进包含 NA 值。我现在将检查我的原始数据。再次感谢!
  • 你能看看下面的帖子吗stackoverflow.com/questions/69609589/…>
猜你喜欢
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 2014-10-08
  • 2019-08-01
  • 2020-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多