2015-04-01 69 views
1

我有一個單詞列表,看起來像這樣創造二元語法功能:需要加快是從文本列表

[[1]] [1]「快」,「棕」,「狐狸」「跳躍」

[[2]] [1] 「一次」, 「後」, 「午夜」 「沉悶」

[[3]] [1] 「談論」 「烏鴉」 「永不復」

我想要做的是創建一組基於這個列表的bigrams(這是更大,更大的一個例子)。我的代碼在下面,它可以工作。問題是它太慢了。我知道我在bigram_list()中的循環會減慢它的速度,但我無法弄清楚如何在列表中使用lapply。我也懷疑數據表和rbindlist()會有很大的幫助,但我似乎無法讓它們工作。任何幫助將與哈利路亞的合唱團會面。

bigram_list <- function(words, ng) { 
    tokens <- character() 

    words_length <- length(words) 
    for (i in 1:words_length) { 
     set <- words[[i]]   ##current vector of words 
     end <- length(set) 
     if (end > 2) { 
      if (ng == 1) { 
       nlist <- set[1:(end-1)] 
      } else { 
       nlist <- set[2:end] 
      } 
      tokens <- c(tokens,nlist) 
     } 
    } 
    return(tokens) 
} 

make_bigram <- function(words) { 
    n1s <- character() 
    n2s <- character() 

    n1.set <- bigram_list(words, 1) 
    n1s <- c(n1s, n1.set) 

    n2.set <- bigram_list(words, 2) 
    n2s <- c(n2s, n2.set) 

    bigrams <- data.frame(n1=n1s, n2=n2s) 
    return(bigrams) 
} 
+0

你只需要兩個或兩個bigrams的計數? – thie1e 2015-04-01 19:41:44

+0

我需要實際的bigrams。通過使用數據表,我可以在數據框中獲得這些數據後快速地將它們聚合起來。我的最終目標是一系列bigrams及其頻率。 – Branwen 2015-04-02 00:57:17

回答

0

我在Python做到這一點的方法是:

zip(tokens[:-1],tokens[1:]) 

有有兩件事情:列表切片和拉鍊。

列表切片可以讓您將列表中的部分縮小。在這種情況下,我們實際上分別從列表中刪除最後一個和第一個標記,但只選擇除了片中第一個標記之外的最後一個和所有標記。

zip結合了兩個列表,其中每個列表中的並行條目形成一個元組; R中的mapply似乎與我們的目的相似。

在R,這似乎工作:

> tokens <- list("I", "am", "a", "banana",".") 
> mapply(list,tokens[1:length(tokens)-1], tokens[2:length(tokens)]) 
    [,1] [,2] [,3]  [,4]  
[1,] "I" "am" "a"  "banana" 
[2,] "am" "a" "banana" "."  
+0

這是一個有趣的想法,但我怎樣才能讓它爲整個列表工作?我的短測試集是:l1 < - c(「quick」,「brown」,「fox」,「jumps」) l2 <-c(「once」,「upon」,「midnight」,「dreary」) l3 < - c(「quoth」,「raven」,「nevermore」) Li < - list(l1,l2,l3) – Branwen 2015-04-02 01:06:57

+0

您的列表是單獨的文檔還是句子?你可能不想在句子之間形成大句子。沒有理由在文檔之間形成bigrams。至於遍歷單個列表,使用'for'循環。 – Dan 2015-04-03 19:49:31

0

,僅保留雙字母組可以使用ngram包。它的速度非常快,因爲它是用C語言編寫的。但是,目前的版本似乎只允許導出n-gram而沒有它們各自的頻率。

要獲得頻率,您可以使用tau包。其中包括返回n-gram及其頻率。

在下面的基準中,我們可以看到ngram()textcnt()快得多,但是由於textcnt()也計算頻率,所以比較並不完全公平。

text <- list("This is just an example for Stackoverflow", 
      "The quick brown fox jumps over the lazy dog", 
      "And another example sentence to test the function", 
      "This is the end of the list") 
# Repeat to make the list larger 
text <- rep(text, 1000) 

### Using the tau package -------------------------------- 
library(tau) 
# Find and count n-grams. Treats list elements separately. 
# (For example there is no bigram "stackoverflow the") 
ngrams <- textcnt(text, method = "string", n = 2L, decreasing = T) 
# > head(ngrams, 3) 
# this is  an example  and another 
# 2000   1000   1000 

## Apply over separate list elements 
ngrams <- lapply(text, 
       function(x) textcnt(x, 
            method = "string", 
            n = 2L, 
            decreasing = T)) 

### Using the ngram package ------------------------------- 
# This works only on a string, not a list. 
# Does not return frequencies 
library(ngram) 
ngram <- ngram(paste(unlist(text), collapse = " "), 
       n = 2L) 
ngram <- get.ngrams(ngram) 
# > head(ngram, 3) 
# [1] "just an"  "The quick" "is the" 

### Benchmarks --------------------------------------------- 
library(microbenchmark) 
microbenchmark(ngram(paste(unlist(text), collapse = " "), 
           n = 2L)) 
# mean 34.3, median 33.7 
microbenchmark(textcnt(text, method = "string", n = 2L, decreasing = T)) 
# mean 223.7, median 220.6