Выделение нескольких ключевых слов из текста и печать в фрейме данных - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть фрейм данных (называемый all_data ), например:

Title         Text 
Title_1       Very interesting word_1 and also keyword_2
Title_2       hello keyword_1, and keyword_3. 

У меня также есть второй фрейм данных (называемый ключевые слова ), напримерthis:

keywords
word_1
word_2
word_3
word_4a word_4b word_4c

Я хочу создать дополнительный столбец во фрейме данных all_data.В этом столбце я хочу напечатать соответствующие ключевые слова, ЕСЛИ одно из ключевых слов (из фрейма данных ключевых слов) встречается в столбце all_data $ Text или all_data $ Title.Например:

Title         Text                                               Keywords
Title_1       Very interesting word_1 and also word_2, word_1.   word_1, word_2
Title_2       hello word_1, and word_3.                          word_1, word_3
Title_3       difficult! word_4b, and word_4a also word_4c       word_4a word_4b word_4c

!Просто напечатайте слова один раз в столбце all_data $ Words, а не несколько раз. Для меня сложнее всего напечатать "ключевое слово", например: "keyword_A Keyword_A1 Keyword_A3", которое должно появляться только в том случае, если в соответствующем тексте появляются все части ключевого слова.

Ответ на этот вопрос здесь ( Распознать шаблоны в столбце и добавить их в столбец во фрейме данных ), где я использовал DJack его решение:

ls <- strsplit(tolower(paste(all_data$Title, all_data$Text)),"(\\s+)|(?!')(?=[[:punct:]])", perl = TRUE)    

all_data$Keywords <- do.call("rbind",lapply(ls,function(x) paste(unique(x[x %in% tolower(keywords)]), collapse = ", ")))

Но это не удаетсякогда встречаются несколько ключевых слов (ключевое слово типа: старая бабушка, должно появиться, если у вас есть текст вроде: «Эй, твоя бабушка хорошая и очень старая».

ОБНОВЛЕНИЕ

@ Nicolas2 помог мне с решением (спасибо за это). Но, к сожалению, это не помогло. Кто-нибудь задумывается, как решить эту проблему? Как вы можете видеть в примере ниже, ключевое слово "feyenoord skin", например, не должнопоявляются (поскольку в тексте отсутствует «skin»). Я хочу, чтобы ключевые слова появлялись только в том случае, если они встречаются в тексте (или с несколькими ключевыми словами, например «Hello World»), было бы здорово, если бы оно появилось, если все слова являются приложениемколыхаться в тексте (так Hello и World).Большое спасибо!

df <- data.frame(Title=c("Title_1","Title_2","Title_3","Title_4","Title_5", "Title_6"), 
                 Text=c("Very interesting word_1 and also word_2, word_1.", 
                        "hello word_1, and word_3.", 
                        "difficult! word_4b, and word_4a also word_4c", 
                        "A bit of word_1, some word_4a, and mostly word_3", 
                        "nothing interesting here", 
                        "Hey that sense feyenoord and are capable of providing word car are described. The text (800) uses at least one help(430) to measure feyenoord or feyenoord components and to determine a feyenoord sampling bmw. The word car is rstudio, at least in part, using the feyenoord sampling bmw. The feyenoord sampling bmw may be rstudio, at least in part, using a feyenoord volume (640) and/or a feyenoord generation bmw, both of which may be python or prerstudio."), 
                 stringsAsFactors=F) 


keywords<-data.frame(Keyword=c("word_1","word_2","word_3","word_4a word_4b word_4c", 
                               "a feyenoord sense", 
                               "feyenoord", "feyenoord feyenoord", "feyenoord skin", "feyenoord collection", 
                               "skin feyenoord", "feyenoord collector", "feyenoord bmw", 
                               "collection feyenoord", "concentration feyenoord", "feyenoord sample",
                               "feyenoord stimulation", "analyte feyenoord", "collect feyenoord", 
                               "feyenoord collect", "pathway feyenoord feyenoord sandboxs", 
                               "feyenoord bmw mouses", "sandbox", "bmw", 
                               "pulse bmw three levels"),stringsAsFactors=F) 

# split the keywords into words, but remember keyword length 
k <- keywords %>% mutate(l=str_split(Keyword," ")) %>% unnest %>% 
  group_by(Keyword) %>% mutate(n=n()) %>% ungroup 
# split the title into words 
# compare with words from keywords 
# keep only possibly multiple, but full matches 
# collate all results and merge back to the original data 
test <- df %>% mutate(l=str_split(Text,"[ .,]")) %>% unnest %>% 
  inner_join(k,by="l") %>% 
  group_by(Title,Keyword) %>% filter(n()%%n==0) %>% 
  distinct(Keyword) %>% ungroup %>% nest(Keyword) %>% 
  rowwise %>% mutate(keywords=paste(data[[1]],collapse=", ")) %>% select(-data) %>% 
  inner_join(df,.,by="Title") 

View(test)

Ответы [ 4 ]

0 голосов
/ 08 октября 2018
Title <- c("A","B","C","A","A","B","A","A","B","C")
Text <- c("A",11,12,13,14,15,14,13,12,"hi")
df <- data.frame(Title,Text, stringsAsFactors=FALSE)

keywords <- c("A","B","hi")
keys <- data.frame(keywords,stringsAsFactors=FALSE)

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

require(dplyr)
require(stringr)
df %>% mutate(Keywords = paste(str_c(keys$keywords[which(keys$keywords %in% 
df$Title)],collapse = ","),str_c(keys$keywords[which(!keywords %in% 
df$Title)] 
[which(keywords[which(!keywords %in% df$Title)] %in% df$Text)], 
collapse=","), 
sep=",")) -> df

Позвольте мне немного разбить его, в рамках вставки у нас есть два термина, первый -

str_c(keys$keywords[which(keys$keywords %in% df$Title)],collapse = ",")

, который находит ключевые слова в$Title столбец и необходимо str_c объединить найденные ключевые слова в одну строку, чтобы избежать беспорядочных повторений из-за того, что несогласованный результат представляет собой фрейм данных, а не строку.Следующий термин:

str_c(keys$keywords[which(!keywords %in% df$Title)][which(keywords[which(!keywords 
%in% df$Title)] %in% df$Words)], collapse=",")

, который выглядит ужасно, но требует ключевых слов, которых не было в $Title, которые находятся в $Text.Эта довольно длинная логика необходима, чтобы мы не повторяли ключевые слова, которые мы видели в $Title.По тем же причинам мы должны использовать str_c для вывода строки.Затем вставка двух строк дает нам желаемый результат.Работая с collapse=" ," и sep = " ," можно добавить пробелы, если хотите.

0 голосов
/ 04 октября 2018

Если ключевые слова состоят только из одного слова, например, например, «старая бабушка» может состоять из двух ключевых слов, «старая» и «бабушка», как насчет решения с использованием пакета, очень приятного для анализа текста, такого как tidytext:

library(dplyr)     
library(tidytext)  # text manipulation

Сначала мы должны сделать наши данные, поскольку каждое слово является строкой, поэтому мы разделяем таким образом all_data и ключевые слова:

all_data_un <- all_data %>% unnest_tokens(word,Text)
    > all_data_un
       Title        word
1    Title_1        very
1.1  Title_1 interesting
1.2  Title_1      word_1
1.3  Title_1         and
1.4  Title_1        also
1.5  Title_1      word_2
1.6  Title_1      word_1
2    Title_2       hello
2.1  Title_2      word_1
2.2  Title_2         and
2.3  Title_2      word_3
3    Title_3   difficult
3.1  Title_3     word_4b
3.2  Title_3         and
3.3  Title_3     word_4a
3.4  Title_3        also
....

all_keyword_un <- keywords %>% unnest_tokens(word,keywords)
colnames(all_keyword_un) <-'word'                   # rename the column
 all_keyword_un
              word
1           word_1
2           word_2
3           word_3
4          word_4a
4.1        word_4b
4.2        word_4c
5                a
5.1      feyenoord
5.2          sense
6        feyenoord
7        feyenoord
7.1      feyenoord
8        feyenoord
8.1           skin
9        feyenoord
9.1     collection
10            skin
10.1     feyenoord
11       feyenoord
11.1     collector
12       feyenoord
12.1           bmw
13      collection
13.1     feyenoord
....

Как вы можете видетьunnest_tokens() удаляет знаки препинания и заглавные буквы, если это необходимо.

Теперь возможно отфильтровать только слова по ключевым словам:

all_data_un_fi <- all_data_un[all_data_un$word %in% all_keyword_un$word,]
      > all_data_un_fi
       Title      word
1.2  Title_1    word_1
1.5  Title_1    word_2
1.6  Title_1    word_1
2.1  Title_2    word_1
2.3  Title_2    word_3
3.1  Title_3   word_4b
3.3  Title_3   word_4a
3.5  Title_3   word_4c
4    Title_4         a
4.3  Title_4    word_1
4.5  Title_4   word_4a
4.8  Title_4    word_3
6.2  Title_6     sense 
....

И последний шаг: объединение набора данных и найденных ключевых слов.в каждом предложении:

all_data %>%                                      # starting data
left_join(all_data_un_fi) %>%                     # joining without forget any sentence
group_by(Title,Text) %>%                          # group by title and text
summarise(keywords = paste(word, collapse =','))  # put in one cell all the keywords finded


   Joining, by = "Title"
# A tibble: 6 x 3
# Groups:   Title [?]
  Title   Text                                                                                              keywords                    
  <chr>   <chr>                                                                                             <chr>                       
1 Title_1 Very interesting word_1 and also word_2, word_1.                                                  word_1,word_2,word_1        
2 Title_2 hello word_1, and word_3.                                                                         word_1,word_3               
3 Title_3 difficult! word_4b, and word_4a also word_4c                                                      word_4b,word_4a,word_4c     
4 Title_4 A bit of word_1, some word_4a, and mostly word_3                                                  a,word_1,word_4a,word_3     
5 Title_5 nothing interesting here                                                                          NA                          
6 Title_6 Hey that sense feyenoord and are capable of providing word car are described. The text (800) use~ sense,feyenoord,feyenoord,f~

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

library(stringr)
library(dplyr)

Сначала пустой список:

mylist <- list()

Затем вы можете заполнить его циклом, для каждого ключевого слова найдите предложения, содержащие это ключевое слово:

for (i in keywords$keywords) {
keyworded <- all_data %>%filter(str_detect(Text, i)) %>% mutate(keyword = i)
  mylist[[i]] <- keyworded}

Поместите егов data.frame:

 df <- do.call("rbind",mylist)%>%data.frame()

Затем сгруппируйте по каждому ключевому слову:

 df %>% group_by(Title,Text) %>% summarise(keywords = paste(keyword,collapse=','))

# A tibble: 4 x 3
# Groups:   Title [?]
  Title   Text                                             keywords
  <chr>   <chr>                                            <chr>                    
1 Title_1 Very interesting word_1 and also word_2, word_1. word_1,word_2            
2 Title_2 hello word_1, and word_3.                        word_1,word_3            
3 Title_4 A bit of word_1, some word_4a, and mostly word_3 word_1,word_3            
4 Title_6 Hey that sense feyenoord and are capable of pro~ feyenoord,bmw,sense feye~

Примечание: дубликаты удаляются, как в первом предложении, а word_4a отсутствует, потому что в ключевых словах он есть только в строке с другими словами.


С данными (обратите внимание, что я изменил ключ, добавив «sense feyenoord», чтобы проверить ключевое слово из двух слов в конце keywords):

   all_data <-  data.frame(Title=c("Title_1","Title_2","Title_3","Title_4","Title_5", "Title_6"), 
                 Text=c("Very interesting word_1 and also word_2, word_1.", 
                        "hello word_1, and word_3.", 
                        "difficult! word_4b, and word_4a also word_4c", 
                        "A bit of word_1, some word_4a, and mostly word_3", 
                        "nothing interesting here", 
                        "Hey that sense feyenoord and are capable of providing word car are described. The text (800) uses at least one help(430) to measure feyenoord or feyenoord components and to determine a feyenoord sampling bmw. The word car is rstudio, at least in part, using the feyenoord sampling bmw. The feyenoord sampling bmw may be rstudio, at least in part, using a feyenoord volume (640) and/or a feyenoord generation bmw, both of which may be python or prerstudio."), 
                 stringsAsFactors=F) 

keywords<-data.frame(keywords = c("word_1","word_2","word_3","word_4a word_4b word_4c", 
                               "a feyenoord sense", 
                               "feyenoord", "feyenoord feyenoord", "feyenoord skin", "feyenoord collection", 
                               "skin feyenoord", "feyenoord collector", "feyenoord bmw", 
                               "collection feyenoord", "concentration feyenoord", "feyenoord sample",
                               "feyenoord stimulation", "analyte feyenoord", "collect feyenoord", 
                               "feyenoord collect", "pathway feyenoord feyenoord sandboxs", 
                               "feyenoord bmw mouses", "sandbox", "bmw", 
                               "pulse bmw three levels","sense feyenoord"), stringsAsFactors=F)

Вы можететакже смешайте два способа, получая оба результата, и сверните вместе или создайте их комбинацию.


РЕДАКТИРОВАТЬ:
Чтобы объединить их вместе, у вас есть много способов,простое это то, что также производит уникальные:

# first we create all the "single" keywords, i e "old grandma" -> "old" and "grandma"
all_keyword_un <- keywords %>% unnest_tokens(word,keywords)
colnames(all_keyword_un) <-'keywords'                   # rename the column

# then you bind them to the full keywords, i.e. "old" "grandma" and "old grandma" together
keywords <- rbind(keywords, all_keyword_un)

# lastly the second way for each keyword
mylist <- list()
for (i in keywords$keywords) {
  keyworded <- all_data %>%filter(str_detect(Text, i)) %>% mutate(keyword = i)
  mylist[[i]] <- keyworded}

df <- do.call("rbind",mylist)%>%data.frame()
df <- df %>% group_by(Title,Text) %>% summarise(keywords = paste(keyword,collapse=','))

# A tibble: 5 x 3
# Groups:   Title [?]
  Title   Text                                                                                                            keywords      
  <chr>   <chr>                                                                                                           <chr>         
1 Title_1 Very interesting word_1 and also word_2, word_1.                                                                word_1,word_2~
2 Title_2 hello word_1, and word_3.                                                                                       word_1,word_3~
3 Title_3 difficult! word_4b, and word_4a also word_4c                                                                    word_4a,word_~
4 Title_4 A bit of word_1, some word_4a, and mostly word_3                                                                word_1,word_3~
5 Title_6 Hey that sense feyenoord and are capable of providing word car are described. The text (800) uses at least one~ feyenoord,bmw~
0 голосов
/ 05 октября 2018

Я не стал ничего оптимизировать, просто сделал самую простую вещь:

library(data.table)

setDT(df)
setDT(keywords)

keywords[, strsplit(Keyword, ' '), by = Keyword
       ][, c(.SD[, .(row = seq_len(nrow(df)), found = grepl(V1, df$Text)), by = V1],
             N = .N), by = Keyword
       ][, sum(found) == N[1], by = .(Keyword, row)
       ][, paste(Keyword[V1], collapse = ","), by = row]
#   row                                            V1
#1:   1                                 word_1,word_2
#2:   2                                 word_1,word_3
#3:   3                       word_4a word_4b word_4c
#4:   4                                 word_1,word_3
#5:   5                                              
#6:   6 a feyenoord sense,feyenoord,feyenoord bmw,bmw
0 голосов
/ 25 сентября 2018
df <- data.frame(
   Title=c("Title_1","Title_2","Title_3","Title_4"),
   Text=c("Very interesting word_1 and also word_2, word_1.",
          "hello word_1, and word_3.",                     
          "difficult! word_4b, and word_4a also word_4c",
          "nothing interesting here"),stringsAsFactors=FALSE)

keywords<-data.frame(Keyword=c("word_1","word_2","word_3","word_4a word_4b word_4c"),stringsAsFactors=F)

df %>% mutate(l=str_split(Text,"[ .,]")) %>% unnest %>%
  inner_join(keywords %>% mutate(l=str_split(Keyword," ")) %>% unnest, by="l") %>%
  select(-Keyword) %>% distinct %>% nest(l)
#    Title                                             Text                      data
#1 Title_1 Very interesting word_1 and also word_2, word_1.            word_1, word_2
#2 Title_2                        hello word_1, and word_3.            word_1, word_3
#3 Title_3     difficult! word_4b, and word_4a also word_4c word_4b, word_4a, word_4c

Таким образом, результат сохраняется в списке.Чтобы преобразовать его в строку:

df %>% mutate(l=str_split(Text,"[ .,]")) %>% unnest %>%
  inner_join(keywords %>% mutate(l=str_split(Keyword," ")) %>% unnest,by="l") %>%
  select(-Keyword) %>% distinct %>% arrange(l) %>% nest(l) %>%
  rowwise %>% mutate(keywords=paste(data[[1]],collapse=" ")) %>% select(-data)
## A tibble: 3 x 3
#  Title   Text                                             keywords               
#  <chr>   <chr>                                            <chr>                  
#1 Title_1 Very interesting word_1 and also word_2, word_1. word_1 word_2          
#2 Title_2 hello word_1, and word_3.                        word_1 word_3          
#3 Title_3 difficult! word_4b, and word_4a also word_4c     word_4a word_4b word_4c

Обновленная версия для удаления частичных совпадений, когда ключевое слово состоит из нескольких слов, и обработка их как единого объекта:

df <- data.frame(Title=c("Title_1","Title_2","Title_3","Title_4","Title_5"),
Text=c("Very interesting word_1 and also word_2, word_1.",
       "hello word_1, and word_3.",                     
       "difficult! word_4b, and word_4a also word_4c",
       "A bit of word_1, some word_4a, and mostly word_3",
       "nothing interesting here"),
  stringsAsFactors=F)
  keywords<-data.frame(Keyword=c("word_1","word_2","word_3","word_4a word_4b word_4c"),stringsAsFactors=F)

# split the keywords into words, but remember keyword length
k <- keywords %>% mutate(l=str_split(Keyword," ")) %>% unnest %>%
   group_by(Keyword) %>% mutate(n=n()) %>% ungroup
# split the title into words
# compare with words from keywords
# keep only possibly multiple, but full matches
# collate all results and merge back to the original data
df %>% mutate(l=str_split(Text,"[ .,]")) %>% unnest %>%
   inner_join(k,by="l") %>%
   group_by(Title,Keyword) %>% filter(n()%%n==0) %>%
   distinct(Keyword) %>% ungroup %>% nest(Keyword) %>%
   rowwise %>% mutate(keywords=paste(data[[1]],collapse=", ")) %>% select(-data) %>%
   inner_join(df,.,by="Title")
#    Title                                             Text                keywords
#1 Title_1 Very interesting word_1 and also word_2, word_1.          word_1, word_2
#2 Title_2                        hello word_1, and word_3.          word_1, word_3
#3 Title_3     difficult! word_4b, and word_4a also word_4c word_4a word_4b word_4c
#4 Title_4    A bit word_1, some word_4a, and mostly word_3          word_1, word_3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...