Как представить каждое вхождение слова как отдельный вектор tcm в R?

Я ищу эффективный способ создать матрицу совместной встречаемости терминов для (каждого) целевого слова в корпусе, чтобы каждое вхождение слова составляло свой собственный вектор (строку) в tcm , где столбцы - это контекстные слова (т. е. модель совместной встречаемости на основе токенов). Это контрастирует с более распространенной оценкой, используемой в векторной семантике, где каждый термин (тип) получает строку и столбец в симметричном tcm, а значения агрегируются по (совместным) вхождениям токенов типов.

Очевидно, это можно сделать с нуля, используя базовую функциональность R, или взломать, отфильтровав tcm, сгенерированный одним из существующих пакетов, которые это делают, но данные корпуса, с которыми я имею дело, довольно большие (миллионы слов) - и есть уже доступные пакеты corpus / NLP для R, которые эффективно выполняют такого рода задачи и сохраняют результаты в удобных для памяти разреженных матрицах, таких как text2vec (функция tcm), quanteda (fcm) и tidytext (cast_dtm). Поэтому не имеет смысла изобретать велосипед (с точки зрения итераторов, хеширования и прочего). Но я также не могу найти простой способ создать tcm на основе токенов с любым из них; отсюда и этот вопрос.

Минимальный пример:

  library(text2vec)
  library(Matrix)
  library(magrittr)

  # default approach to tcm with text2vec:
  corpus = strsplit(c("here is a short document", "here is a different short document"), " ")
  it = itoken(corpus) 
  tcm = create_vocabulary(it)  %>% vocab_vectorizer() %>% create_tcm(it, . , skip_grams_window = 2, weights = rep(1,2))

  # results in this:
  print(as.matrix(forceSymmetric(tcm, "U")))

            different here short document is a
  different         0    0     1        1  1 1
  here              0    0     0        0  2 2
  short             1    0     0        2  1 2
  document          1    0     2        0  0 1
  is                1    2     1        0  0 2
  a                 1    2     2        1  2 0

Попытка получить модель на основе токенов, для целевого слова «короткий»:

  i=0
  corpus = lapply(corpus, function(x) 
   ifelse(x == "short", {i<<-i+1;paste0("short", i)}, x  ) 
   ) # appends index to each occurrence so itoken distinguishes them
  it = itoken(corpus) 
  tcm = create_vocabulary(it)  %>% vocab_vectorizer() %>% create_tcm(it, . , skip_grams_window = 2, weights = rep(1,2))
  attempt = as.matrix(forceSymmetric(tcm, "U") %>% 
   .[grep("^short", rownames(.)), -grep("^short", colnames(.))] 
   ) # filters the resulting full tcm

  # yields intended result but is hacky/slow:
  print(attempt)

         different here document is a
  short2         1    0        1  0 1
  short1         0    0        1  1 1

Что является лучшей / более быстрой альтернативой этому подходу для получения tcm на основе токенов, как в последнем примере? (возможно, используя один из пакетов R, который уже выполняет tcms на основе типов)


person user3554004    schedule 23.10.2018    source источник
comment
@phiver удален; Я получил невнятную ошибку, пытаясь опубликовать первоначально, поэтому я попытался снова, но, очевидно, сообщение прошло в первый раз, несмотря на ошибку.   -  person user3554004    schedule 23.10.2018


Ответы (1)


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

Из примера видно, что вам нужно контекстное окно из +/- 2 слов, поэтому я сделал это для целевого слова «короткий».

Сначала мы получаем контекст, используя ключевые слова в контексте:

library("quanteda")
txt <- c("here is a short document", "here is a different short document")

(shortkwic <- kwic(txt, "short", window = 2))
#                                          
# [text1, 4]        is a | short | document
# [text2, 5] a different | short | document

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

shortcorp <- corpus(shortkwic, split_context = FALSE, extract_keyword = TRUE)
docnames(shortcorp) <- make.unique(docvars(shortcorp, "keyword"))
texts(shortcorp)
#                 short                      short.1 
# "is a short document" "a different short document" 

Затем создайте dfm, выбрав все слова, но удалив цель:

dfm(shortcorp) %>%
  dfm_select(dfm(txt)) %>%
  dfm_remove("short")
# Document-feature matrix of: 2 documents, 5 features (40% sparse).
# 2 x 5 sparse Matrix of class "dfm"
#          features
# docs      here is a document different
#   short      0  1 1        1         0
#   short.1    0  0 1        1         1
person Ken Benoit    schedule 23.10.2018