Используйте динамическую (переменную) строку в качестве шаблона регулярного выражения в R - PullRequest
0 голосов
/ 24 мая 2018

У меня есть data.table DT_words (большое измерение):

DT_words <- data.table(word = c('word1', 'word2', 'word3','word4'))

У меня есть еще одна data.table DT_strings, которая содержит столбец с большим количеством строк

DT_strings <- data.table(string = c('string1 made of word1', 'string2 made of word2 and word2 and word3 and word1ly', 'string3 made of word1 and word2'))

для каждого слова в DT_word я хотел бы подсчитать общее количество вхождений во всех строках в DT_string и сохранить это значение в виде столбца в DT_word.Я использую циклы for, и это выглядит ужасно.

Я пытался использовать lapply и mapply, но безрезультатно, поскольку функция требует внутреннего ввода.

Вот цикл forэти слова (но это очень долго и некрасиво)

require(stringr)

for (i in 1:nrow(DT_words))
{
   DT_words$word_count[i] <-  sum(str_count(DT_strings$string, 
                                  paste0(c("\\b("),paste(DT_words[i, .(word)]),c(")\\b"))))
}

Я знаю, что формат - это скорее data.frame, но поскольку я использую цикл, это не имеет значения,Является ли?В любом случае, мне было интересно, смогу ли я использовать apply в data.table и избавиться от этого уродства.

Желания будут:

> DT_words
    word word_count
1: word1          2
2: word2          3
3: word3          1
4: word4          0

Редактировать: я отредактировал DT_strings, чтобы включить больше примеровсоответствия слов.Меня интересует только сопоставление целого слова, поэтому синтаксис регулярных выражений должен быть как-то включен.

Ответы [ 3 ]

0 голосов
/ 24 мая 2018

Предполагая, что то, что вы называете строками и словами, происходит от естественного языка, я предлагаю следующее базовое решение R, которое, возможно, работает быстрее.Суть в том, что вы должны разделять разные слова в строках, но легко адаптировать 'strsplit' к другим разделителям.

s <- c('string1 made of word1', 'string2 made of word2 and word2 and word3', 'string3 made of word1 and word2')
w <- c('word1', 'word2', 'word3','word4')

z <- as.data.frame(table(unlist(strsplit(s,' '))))
z[z$Var1 %in% w,]

#   Var1 Freq
#7 word1    2
#8 word2    3
#9 word3    1
0 голосов
/ 24 мая 2018

Если ваши слова действительно разделены пробелом, я бы разделил их на столбцы, преобразовал в длинный формат и затем запустил двоичное объединение в сочетании с by = .EACHI, например, используя ваши данные:

library(data.table)
library(magrittr)                       
DT_strings[, tstrsplit(string, " ", fixed = TRUE)] %>% 
  melt(., measure.vars = names(.), na.rm = TRUE) %>%
  .[DT_words, on = .(value = word), .N, by = .EACHI]
#    value N
# 1: word1 2
# 2: word2 3
# 3: word3 1
# 4: word4 0

PS

Я использовал fixed = TRUE для скорости, так как я предполагал, что между каждым словом всегда один пробел.Если количество пробелов меняется, вам нужно использовать tstrsplit(string, "\\s+"), что, вероятно, будет медленнее.

0 голосов
/ 24 мая 2018

Вот решение с использованием пакета tidyverse.

library(stringr)
library(purrr)

DT_words$word_count <- map_int(paste0("\\b", DT_words$word,"\\b"),
   ~ str_count(DT_strings$string, .x) %>% sum)

Альтернатива, в которой не используется purrr:

DT_words$word_count <- vapply(paste0("\\b", DT_words$word, "\\b"), function(x) {
  sum(str_count(DT_strings$string, x))
}, 0)
...