В R, сопоставление количества отдельных слов и количества слов в словаре

#r #nlp #quanteda

#r #nlp #quanteda

Вопрос:

Мне нужно посчитать слова в документе. В некоторых случаях мне нужно подсчитать конкретные слова (например, «свежий»), в других случаях мне нужно получить общее количество набора слов («филадельфия», «тетя»).).

Я знаю, как сделать это в два отдельных шага (см. Код ниже), но как я могу сделать это одновременно?

Приведенный ниже код подсчитывает конкретные слова.

 library("quanteda")
txt <- "In west Philadelphia born and raised On the playground was where I spent most of my days Chillin' out maxin' relaxin' all cool And all shootin some b-ball outside of the school When a couple of guys who were up to no good Started making trouble in my neighborhood I got in one little fight and my mom got scared."
tokens(txt) %>% tokens_select(c("trouble", "fight")) %>% dfm()
 

Вывод:

 trouble, fight
1, 1
 

Приведенный ниже код подсчитывает словарные слова и записывает общее количество в один столбец.

 mydict <- dictionary(list(all_terms = c("chillin", "relaxin", "shootin")))
count <-dfm(txt,dictionary = mydict)
 

Вывод:

 all_terms
3
 

Как я могу объединить их?

Я хотел бы что-то вроде этого: (код гипотетический и НЕ работает)

 tokens(txt) %>% tokens_select(c("trouble", "fight"), mydict) %>% dfm()
 

или

 tokens(txt) %>% tokens_select(c("trouble", "fight"), all_terms=c("chillin","relaxin","shootin")) %>% dfm()
 

Желаемый результат:

 trouble, fight, all_terms
1, 1, 3
 

Ответ №1:

Есть несколько способов, это, вероятно, самый простой. Определите словарь, в котором ключ равен значению слова для каждого конкретного слова, и ключ группы для наборов слов — в вашем примере «all_terms».

 library("quanteda")
## Package version: 2.1.2

txt <- "In west Philadelphia born and raised On the playground was where I spent most of my days Chillin' out maxin' relaxin' all cool And all shootin some b-ball outside of the school When a couple of guys who were up to no good Started making trouble in my neighborhood I got in one little fight and my mom got scared."

dict <- dictionary(list(
  trouble = "trouble",
  fight = "fight",
  all_terms = c("chillin", "relaxin", "shootin")
))
 

Теперь, когда вы скомпилируете dfm, вы получите то, что вам нужно.

 dfmat <- dfm(txt, dictionary = dict)
dfmat
## Document-feature matrix of: 1 document, 3 features (0.0% sparse).
##        features
## docs    trouble fight all_terms
##   text1       1     1         3
 

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

 # as a named numeric vector
structure(as.vector(dfmat), names = featnames(dfmat))
##   trouble     fight all_terms 
##         1         1         3

# per your output
cat(
  paste(featnames(dfmat), collapse = ", "), "n",
  paste(as.vector(dfmat), collapse = ", ")
)
## trouble, fight, all_terms 
##  1, 1, 3
 

Обратите внимание, что не рекомендуется (как и в другом ответе) напрямую обращаться к внутренним элементам объекта. Вместо этого используйте функции извлечения, такие как featnames() .

Добавлено:

Альтернативный способ без создания именованного списка элементов:

 dict <- dictionary(list(all_terms = c("chillin", "relaxin", "shootin")))
single_words <- c("trouble", "fight")

tokens(txt) %>%
  tokens_lookup(dictionary = dict, exclusive = FALSE) %>%
  tokens_keep(pattern = c(names(dict), single_words)) %>%
  dfm()
## Document-feature matrix of: 1 document, 3 features (0.0% sparse).
##        features
## docs    all_terms trouble fight
##   text1         3       1     1
 

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

1. Разве это не проще, если вы используете dfm_lookup(exclusive = FALSE) ?

2. Спасибо! Значит, нет способа избежать двойного ввода отдельных терминов (trouble = "trouble") ? Как и в tokens(txt) %>% tokens_select(c("trouble", "fight")) .

3. @KoheiWatanabe, не могли бы вы уточнить? Звучит интересно.

Ответ №2:

Важна ли краткость, т. Е. Все это в одной строке? Если нет, решением является извлечение данных из объектов dfm, а затем объединение в нужную вам форму — matrix, data.frame, tibble.

 library("quanteda")
library(magritte) # for the pipe
txt <- "In west Philadelphia born and raised On the playground was where I spent most of my days Chillin' out maxin' relaxin' all cool And all shootin some b-ball outside of the school When a couple of guys who were up to no good Started making trouble in     my neighborhood I got in one little fight and my mom got scared."
mydict <- dictionary(list(all_terms = c("chillin", "relaxin", "shootin")))

first <-  dfm(tokens_select(tokens(txt), c("trouble", "fight")))
second <- dfm(txt,dictionary = mydict)

# These are the outputs you're after
first@Dimnames$features
first@x

second@Dimnames$features
second@x

# Combine into a matrix
 matrix(c(first@Dimnames$features, second@Dimnames$features), ncol = 3) %>% 
   rbind(c(first@x, second@x))

# Or make two vectors for use elsewhere
  paste(c(first@Dimnames$features, second@Dimnames$features), collapse = ", ")
  paste(c(first@x, second@x), collapse = ", ")
 

Ответ №3:

Это то, что я предложил в комментарии.

 > library("quanteda")
> txt <- "In west Philadelphia born and raised On the playground was where I spent most of my days Chillin' out maxin' relaxin' all cool And all shootin some b-ball outside of the school When a couple of guys who were up to no good Started making trouble in     my neighborhood I got in one little fight and my mom got scared."
> dict <- dictionary(list(all_terms = c("chillin", "relaxin", "shootin")))
> dfmt <- dfm(txt)
> dfmt_dict <- dfm_lookup(dfmt, dict, exclusive = FALSE, cap = FALSE)
> topfeatures(dfmt_dict)
       in       and        of        my all_terms         '       the         i 
        3         3         3         3         3         3         2         2 
      all       got 
        2         2