2011-09-29 6 views
16

J'utilise NLTK pour rechercher des n-grammes dans un corpus, mais cela prend beaucoup de temps dans certains cas. J'ai remarqué que calculer des n-grammes n'est pas une caractéristique rare dans d'autres paquets (apparemment, Haystack a des fonctionnalités pour cela). Cela signifie-t-il qu'il existe une façon potentiellement plus rapide de trouver des n-grammes dans mon corpus si j'abandonne le NLTK? Si oui, que puis-je utiliser pour accélérer les choses?Calcul rapide n-gram

+0

Plus de lecture pour ceux intéressés: http://packages.python.org/Whoosh/ngram s.html – Trindaz

+0

Question connexe: http://stackoverflow.com/questions/21883108/fast-optimize-n-gram-implementations-in-python – dmcc

Répondre

21

Puisque vous n'avez pas indiqué si vous voulez des mots ou des n-grammes au niveau du personnage, je vais juste supposer le premier, sans perte de généralité.

Je suppose également que vous commencez avec une liste de jetons, représentés par des chaînes. Ce que vous pouvez facilement faire est d'écrire vous même l'extraction de n-gram.

def ngrams(tokens, MIN_N, MAX_N): 
    n_tokens = len(tokens) 
    for i in xrange(n_tokens): 
     for j in xrange(i+MIN_N, min(n_tokens, i+MAX_N)+1): 
      yield tokens[i:j] 

Remplacez ensuite le yield avec l'action réelle que vous voulez prendre chaque n-gramme (ajouter à un dict, le stocker dans une base de données, peu importe) pour se débarrasser de la surcharge du générateur. Enfin, si ce n'est pas vraiment assez rapide, convertissez ce qui précède en Cython et compilez-le. Exemple d'utilisation d'un defaultdict au lieu de yield:

def ngrams(tokens, int MIN_N, int MAX_N): 
    cdef Py_ssize_t i, j, n_tokens 

    count = defaultdict(int) 

    join_spaces = " ".join 

    n_tokens = len(tokens) 
    for i in xrange(n_tokens): 
     for j in xrange(i+MIN_N, min(n_tokens, i+MAX_N)+1): 
      count[join_spaces(tokens[i:j])] += 1 

    return count 
+2

Les nouvelles versions de Cython reconnaissent Python pour les instructions et les accélèrent si possible. De plus, vous avez une méthode de recherche dans l'itération interne. définir 'tokenjoiner = "" .join' en dehors de la boucle et en remplaçant l'intérieur "" .join devrait accélérer les choses. – rocksportrocker

+0

@rocksportrocker: bon endroit, a ajouté votre suggestion. –

+0

et vous pouvez réécrire la ligne interne avec "count.get (....) + = 1" introduire un autre var pour éviter la recherche de méthode. – rocksportrocker

7

Vous trouverez peut-être un pythonique, la fonction élégante et rapide génération ngram utilisant zip et floc (*) opérateur here:

def find_ngrams(input_list, n): 
    return zip(*[input_list[i:] for i in range(n)]) 
0

Pour caractère niveau n grammes que vous pourriez utiliser la fonction suivante

def ngrams(text, n): 
    n-=1 
    return [text[i-n:i+1] for i,char in enumerate(text)][n:] 
Questions connexes