Мы могли бы paste
их вместе и обернуть в regex
вместо fixed
. В dplyr
1.0.0 добавлено несколько функций, одна из которых across
library(dplyr) #1.0.0
library(stringr)
test_df %>%
mutate(matches = str_extract_all(text,
pattern = regex(str_c(keywords, collapse = "|"))))
Если нам нужен окончательный ожидаемый результат, после создания столбца list
в matches
, unnest
, чтобы развернуть строки, получите count
и измените его на «широкий» формат с помощью pivot_wider
library(tidyr)
test_df %>%
mutate(matches = str_extract_all(test_df$text, pattern = regex(str_c(keywords, collapse = "|")))) %>%
unnest(c(matches)) %>%
count(across(doc_id:matches)) %>%
pivot_wider(names_from = matches, values_from = n, values_fill = list(n = 0))
# A tibble: 4 x 6
# doc_id text water alcohol gasoline h2o
# <chr> <chr> <int> <int> <int> <int>
#1 doc1 This text refers to water 1 0 0 0
#2 doc2 This text refers to water and alcohol 1 1 0 0
#3 doc4 This text refers to gasoline and more gasoline 0 0 2 0
#4 doc5 This text refers to (h2o) 0 0 0 1
Если у нас есть dplyr
<1.0.0, вместо <code>across просто укажите имена столбцов в count
... %>%
count(doc_id, text, matches)
... %>%
Или преобразуйте имена столбцов в символы и оценить
... %>%
count(!!! rlang::syms(names(.)))
... %>%
В указанном выше методе 'doc3' удаляется, так как совпадений не было. Если нам нужно его оставить, укажите keep_empty = TRUE
в unnest
test_df %>%
mutate(matches = str_extract_all(test_df$text,
pattern = regex(str_c(keywords, collapse = "|")))) %>%
unnest(c(matches), keep_empty = TRUE) %>%
count(across(doc_id:matches)) %>%
mutate(n = replace(n, is.na(matches), 0)) %>%
pivot_wider(names_from = matches, values_from = n, values_fill = list(n = 0)) %>%
select(-`NA`)
# A tibble: 5 x 6
# doc_id text water alcohol gasoline h2o
# <chr> <chr> <dbl> <dbl> <dbl> <dbl>
#1 doc1 This text refers to water 1 0 0 0
#2 doc2 This text refers to water and alcohol 1 1 0 0
#3 doc3 This text refers to alcoolh 0 0 0 0
#4 doc4 This text refers to gasoline and more gasoline 0 0 2 0
#5 doc5 This text refers to (h2o) 0 0 0 1
В дополнение к описанному выше методу более простой вариант - использовать str_count
library(purrr)
map_dfc(set_names(keywords, keywords), ~
str_count(test_df$text, .x)) %>%
bind_cols(test_df, .)
# doc_id text water alcohol gasoline (h2o)
#1 doc1 This text refers to water 1 0 0 0
#2 doc2 This text refers to water and alcohol 1 1 0 0
#3 doc3 This text refers to alcoolh 0 0 0 0
#4 doc4 This text refers to gasoline and more gasoline 0 0 2 0
#5 doc5 This text refers to (h2o) 0 0 0 1
Или используя base R
test_df[keywords] <- lapply(keywords, function(x)
lengths(regmatches(test_df$text, gregexpr(x, test_df$text))))
Хотя str_extract
векторизован для pattern
, длина pattern
будет такой же, как длина столбца, и будет выполняться соответствующее извлечение