R: Как улучшить производительность grepl в функции apply внутри dataframe - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть фрейм данных с приведенными ниже столбцами:

country<- c("CA","IN","US")
text   <- c("paint red green", "painting red", "painting blue")
word   <- c("green, red, blue", "red", "red, blue")
df     <- data.frame(country, text, word)

Для каждой строки я хочу найти слова в столбце слов внутри текста в текстовом столбце и представить их в новом столбце, поэтому в тексте будут показаны найденные слова, разделенные запятой. поэтому новый столбец должен выглядеть так:

df$new_col   <- c("green,red","red","blue")

Я использую эти строки кода, но для запуска и даже свертывания требуется много времени.

setDT(df)[, new_col:= paste(df$word[unlist(lapply(df$word,function(x) grepl(x, df$text,
     ignore.case = T)))], collapse = ","), by = 1:nrow(df)]

Есть ли способ изменить код, чтобы он был более эффективным?

Большое спасибо!

Ответы [ 3 ]

4 голосов
/ 13 февраля 2020

Попробуйте это

mapply(function(x,y){paste(intersect(x,y),collapse=", ")},
       strsplit(as.character(df$text),"\\, | "),
       strsplit(as.character(df$word),"\\, | "))

[1] "red, green" "red"        "blue"
1 голос
/ 13 февраля 2020

Другое базовое решение R, использующее mapply + grep + regmatches, то есть

df <- within(df, newcol <- mapply(function(x,y) toString(grep(x,y,value = TRUE)), 
                                  gsub("\\W+","|",word), 
                                  regmatches(text,gregexpr("\\w+",text))))

, такое что

> df
  country            text             word     newcol
1      CA paint red green green, red, blue red, green
2      IN    painting red              red        red
3      US   painting blue        red, blue       blue
1 голос
/ 13 февраля 2020
library(tidyverse)    
df %>% 
   mutate(newcol = stringr::str_extract_all(text,gsub(", +","|",word)))
      country            text             word     newcol
    1      CA paint red green green, red, blue red, green
    2      IN    painting red              red        red
    3      US   painting blue        red, blue       blue

В этом случае newcol - это список. Чтобы сделать это строкой, мы можем сделать:

df%>%
  mutate(newcol = text %>%
           str_extract_all(gsub(", +", "|", word)) %>%
           invoke(toString, .))

с data.table, вы можете сделать:

 df[,id := .I][,newcol := do.call(toString,str_extract_all(text,gsub(', +',"|",word))),
      by = id][, id := NULL][]
   country            text             word     newcol
1:      CA paint red green green, red, blue red, green
2:      IN    painting red              red        red
3:      US   painting blue        red, blue       blue
...