2017-01-25 34 views
1

Мне нужно использовать лексические данные от Google Books N-grams для построения (разреженной!) Матрицы временных совпадений (где строки - слова и столбцы - это одни и те же слова, а ячейки отражают, сколько раз они появляются в одном и том же окне контекста). Получившийся tcm затем будет использоваться для измерения кучи лексической статистики и служит в качестве входных данных в методах векторной семантики (перчатка, LSA, LDA).Эффективно выводить матрицу совпадений сроков из Google Nграмм

Для справки Google Books (v2) набор данных в следующем формате (разделенные табуляцией)

ngram  year match_count volume_count 
some word 1999 32    12   # example bigram 

Однако, проблема, конечно, эти данные будут superhuge. Хотя мне понадобится только часть данных из нескольких десятилетий (около 20 лет для ngrams), и я доволен контекстным окном до 2 (т. Е. Использую триграмм corpus). У меня есть несколько идей, но никто не кажется особенно, хорошо, хорошо.

-Idea 1- первоначально был более или менее это:

# preprocessing (pseudo) 
for file in trigram-files: 
    download $file 
    filter $lines where 'year' tag matches one of years of interest 
    find the frequency of each of those ngrams (match_count) 
    cat those $lines * $match_count >> file2 
    # (write the same line x times according to the match_count tag) 
    remove $file 

# tcm construction (using R) 
grams <- # read lines from file2 into list 
library(text2vec) 
# treat lines (ngrams) as documents to avoid unrelated ngram overlap 
it   <- itoken(grams) 
vocab  <- create_vocabulary(it) 
vectorizer <- vocab_vectorizer(vocab, skip_grams_window = 2) 
tcm  <- create_tcm(it, vectorizer) # nice and sparse 

Однако, у меня есть подозрение, что это не может быть лучшим решением. Файлы данных ngram уже содержат данные совместного ввода в виде n-граммов, и есть тег, который дает частоту. Я чувствую, что должен быть более прямой путь.

-Idea 2- Я также думал о cat'ing каждый отфильтрованный Ngram только один раз в новый файл (вместо того, чтобы копировать его match_count раз), затем создать пустой кубометр, а затем цикл по всей (год- отфильтрованный) набор данных ngram и записи (с использованием тега match_count), где любые два слова совпадают, чтобы заполнить tcm. Но, опять же, данные большие, и такой цикл, вероятно, займет много времени.

-Idea 3- я нашел библиотеку Python под названием google-ngram-downloader, который, видимо, имеет функцию создания матрицы смежности, но глядя на коде, он будет создавать регулярные (не разреженные) матрицы (которая будет массовой, поскольку большинство записей равно 0s), и (если бы я понял это правильно), это просто loops through everything (и я предполагаю, что цикл Python над этим большим количеством данных будет superslow), поэтому он, похоже, больше нацелен на относительно меньшие подмножества данных.

редактировать-Idea 4- Наткнулся this old SO question с просьбой об использовании Hadoop и Hive для аналогичной задачи, с аа короткого ответа со сломанной ссылкой и комментарием о MapReduce (ни один из которых я знаком с, так Я не знаю, с чего начать).


Но я имею в виду, я не могу быть первым с необходимостью решать такую ​​задачу, учитывая популярность набора данных Ngram и популярность (не word2vec) распределенной семантике методы, которые работают на входе tcm или dtm; следовательно, ->

... вопрос: что было бы более разумным/эффективным способом построения терминологической матрицы совпадения из данных Google Books Ngram? (будь то вариация предлагаемых идей чего-то совершенно другого, R предпочтительным, но не необходимым)

+0

Можете ли вы привести пример, который вы рассчитывать со-occurecesies для три- граммов? Как это должно выглядеть. –

+0

Ну, используя подход (возможно наивный) ngrams-as-documents, что-то вроде 'x <- list (c (« this »,« is »,« example »), c (« example »,« it », является")); it <- itoken (x); vocab <- create_vocabulary (it); vectorizer <- vocab_vectorizer (vocab, skip_grams_window = 2); tcm <- create_tcm (it, vectorizer); печать (Vocab); print (tcm) 'Но это похоже на то, чтобы пройти долгий путь (книги/документы -> в ngrams -> import ngrams как docs -> создать skipgrams из ngrams -> create_tcm), в то время как ngram по существу утверждает факт co -ccurrence уже, и данные дают количество, сколько раз любая ngram происходит – user3554004

ответ

0

Я дам представление о том, как вы можете это сделать. Но его можно улучшить в нескольких местах.Я специально написал в «спагетти-стиль» для лучшего интерпретируемости, но она может быть обобщена на более чем три-грамм

ngram_dt = data.table(ngram = c("as we know", "i know you"), match_count = c(32, 54)) 
# here we split tri-grams to obtain words 
tokens_matrix = strsplit(ngram_dt$ngram, " ", fixed = T) %>% simplify2array() 

# vocab here is vocabulary from chunk, but you can be interested first 
# to create vocabulary from whole corpus of ngrams and filter non 
# interesting/rare words 

vocab = unique(tokens_matrix) 
# convert char matrix to integer matrix for faster downstream calculations 
tokens_matrix_int = match(tokens_matrix, vocab) 
dim(tokens_matrix_int) = dim(tokens_matrix) 

ngram_dt[, token_1 := tokens_matrix_int[1, ]] 
ngram_dt[, token_2 := tokens_matrix_int[2, ]] 
ngram_dt[, token_3 := tokens_matrix_int[3, ]] 

dt_12 = ngram_dt[, .(cnt = sum(match_count)), keyby = .(token_1, token_2)] 
dt_23 = ngram_dt[, .(cnt = sum(match_count)), keyby = .(token_2, token_3)] 
# note here 0.5 - discount for more distant word - we follow text2vec discount of 1/distance 
dt_13 = ngram_dt[, .(cnt = 0.5 * sum(match_count)), keyby = .(token_1, token_3)] 

dt = rbindlist(list(dt_12, dt_13, dt_23)) 
# "reduce" by word indices again - sum pair co-occurences which were in different tri-grams 
dt = dt[, .(cnt = sum(cnt)), keyby = .(token_1, token_2)] 

tcm = Matrix::sparseMatrix(i = dt$token_1, j = dt$token_2, x = dt$cnt, dims = rep(length(vocab), 2), index1 = T, 
        giveCsparse = F, check = F, dimnames = list(vocab, vocab))