понимание подсчитайте количество вхождений шаблона в строку

#r #string #dataframe #tidyverse

Вопрос:

мой вклад:

 library(tidyverse)
library(stringi)
tdf<-data.frame("foo"=c('|ReviewNG-BB.2|ReviewNG-BB.3','|ReviewNG-BB.2|ReviewNG-BB.3','|ReviewNG-BB.2|ReviewNG-BB.3','|ReviewNG-BB.2|ReviewNG-BB.3','|ReviewNG-BB.2|ReviewNG-BB.3','|ReviewNG-BB.2|NG-BB.3','|ReviewNG-BB.2|NG-BB.3','|ReviewNG-BB.2|NG-BB.3','|ReviewNG-BB.2|NG-BB.3','|ReviewNG-BB.2|NG-BB.3','|ReviewNG-BB.2|NG-BB.3','|TI'), 
"bar"=c('|AI|BB.2','|AI|BB.2','|AI|BB.2','|AI|BB.2','|AI|BB.2','|AI|BB.2','|AI|BB.2','|AI|ReviewNG-BB.2','|AI|ReviewNG-BB.2','|AI|ReviewNG-BB.2','|AI|ReviewNG-BB.2','|AI'), 
                 "xyz" = c('|ICV|NG-AI','|ICV|NG-AI','|ICV|NG-AI','|ICV|NG-AI','|ICV|NG-AI','|ICV|NG-AI','|ICV|NG-AI','|ReviewNG-ICV|TI|BB.2',
'|ReviewNG-ICV|TI|BB.2','|ReviewNG-ICV|TI|BB.2','|ReviewNG-ICV|TI|BB.2','|ICV'),
                 "gaz" = c('|BB.3|ReviewNG-AI|NG-TI','|BB.3|ReviewNG-AI|NG-TI','|BB.3|ReviewNG-AI|NG-TI','|BB.3|ReviewNG-AI|NG-TI',
'|BB.3|ReviewNG-AI|NG-TI','|BB.3|ReviewNG-AI|NG-TI','|BB.3|ReviewNG-AI|NG-TI','|NG-BB.2|ICV|AI|TI','|NG-BB.2|ICV|AI|TI','|NG-BB.2|ICV|AI|TI',
'|NG-BB.2|ICV|AI|TI','|BB.2'))
 

Я пытаюсь подсчитать количество вхождений каждой метки в моей tdf , все метки имеют 4 «формы»: общее количество вхождений, ReviewNG-label , NG-label и, по крайней мере, «чистые» |label, |label| . Например, метка AI , есть все совпадения всего, есть ReviewNG-AI NG-AI , и |AI или |AI| чистая форма. Так что мой код:

 pt_t <- c("AI" )
sum(stringi::stri_count_fixed(tdf, regex(pt_t)))
pt_rng <- c("ReviewNG-AI")
sum(stringi::stri_count_fixed(tdf, regex(pt_rng)))
pt_ng<-c("NG-AI")
sum(stringi::stri_count_fixed(tdf, regex(pt_ng)))
pt<-c("|AI","|AI|")
sum(stringi::stri_count_fixed(tdf, regex(pt)))
 

И мой результат:

 Warning in stringi::stri_count_fixed(tdf, regex(pt_t)) :
  argument is not an atomic vector; coercing
[1] 30
Warning in stringi::stri_count_fixed(tdf, regex(pt_rng)) :
  argument is not an atomic vector; coercing
[1] 7
Warning in stringi::stri_count_fixed(tdf, regex(pt_ng)) :
  argument is not an atomic vector; coercing
[1] 14
Warning in stringi::stri_count_fixed(tdf, regex(pt)) :
  argument is not an atomic vector; coercing
[1] 15
 

Во-первых, я не совсем понимаю предупреждающее сообщение.
Теперь давайте посмотрим на подсчет: в целом все в порядке, по ReviewNG-AI -прежнему хорошо. Но следующая проблема:
для NG-AI Я понимаю , что это двойной счет NG плюс ReviewNG , и последний «чистый» счет, потому |AI' or '|AI| что я совершенно не понимаю, как это равно 15, где вручную я считаю 16.

Я тоже пытаюсь stringr , tidyverse но здесь действительно ошибочный вывод:

 sum(str_count(tdf,pt))

res<-tdf %>% 
  summarise(across(everything(),
                   ~sum(str_count(.x, paste(pt)))))

rowSums(res)
 

Комментарии:

1. Разделена ли каждая метка на | ?

Ответ №1:

Ваша проблема здесь заключается в использовании специального символа в регулярном выражении: | зарезервировано для or регулярного выражения. Если мы хотим искать | , нам нужно сбежать с \| помощью . Так, например:

 library(dplyr)
library(stringr)

pt <- c("\|AI", "\|AI\|")
 

Теперь мы хотим подсчитать каждое появление |AI и |AI| , поэтому шаблон поиска выглядит следующим образом:

 paste(pt, collapse = "|")
#> [1] "\|AI|\|AI\|"
 

Итак, складываем все это вместе:

 tdf %>% 
  summarise(across(everything(),
                   ~sum(str_count(.x, paste(pt, collapse = "|")))))
 

ВОЗВРАТ

   foo bar xyz gaz
1   0  12   0   4
 

Комментарии:

1. есть еще одна проблема, если у метки есть проблемы(например Out PPS ), подсчет неверен

2. Не могли бы вы, пожалуйста, прояснить проблему? Что вы имеете в Out PPS виду под этим ? Где возникает ошибка и что вы ожидаете в качестве вывода?

3. Извините, я виноват, что использую // вместо» `

Ответ №2:

Может быть, такое решение. Как Мартин уже объяснил, почему и как мы могли бы использовать другую стратегию. Если все метки разделены |

мы могли pivot_longer бы и count их. В зависимости от желаемого результата:

 library(dplyr)
library(tidyr)

tdf %>% 
  pivot_longer(
    everything()
  ) %>% 
  mutate(value = sub('\|', '', value)) %>% 
  separate_rows(value, sep = "\|") %>% 
  group_by(name, value) %>% 
  summarise(Labels = n())
 
    name  value         Labels
   <chr> <chr>          <int>
 1 bar   AI                12
 2 bar   BB.2               7
 3 bar   ReviewNG-BB.2      4
 4 foo   NG-BB.3            6
 5 foo   ReviewNG-BB.2     11
 6 foo   ReviewNG-BB.3      5
 7 foo   TI                 1
 8 gaz   AI                 4
 9 gaz   BB.2               1
10 gaz   BB.3               7
11 gaz   ICV                4
12 gaz   NG-BB.2            4
13 gaz   NG-TI              7
14 gaz   ReviewNG-AI        7
15 gaz   TI                 4
16 xyz   BB.2               4
17 xyz   ICV                8
18 xyz   NG-AI              7
19 xyz   ReviewNG-ICV       4
20 xyz   TI                 4
 

Комментарии:

1. проблема в моих столбцах df 80