Как предотвратить расщепление определенных слов или фраз и цифр в NLTK? - PullRequest
2 голосов
/ 10 апреля 2019

У меня проблема с сопоставлением текста, когда я токенизирую текст, который разбивает определенные слова, даты и цифры.Как я могу предотвратить расщепление некоторых фраз, таких как «беги в моей семье», «30-минутная прогулка» или «4 раза в день» во время токенизации слов в NLTK?

Они не должны приводить к:

['runs','in','my','family','4x','a','day']

Например:

Да, 20-30 минут в день на моем велосипеде, он отлично работает !!

дает:

['yes','20-30','minutes','a','day','on','my','bike',',','it','works','great']

Я хочу, чтобы слова «20-30 минут» рассматривались как одно слово.Как я могу получить это поведение>?

Ответы [ 2 ]

0 голосов
/ 12 апреля 2019

Вы можете использовать MWETokenizer:

from nltk import word_tokenize
from nltk.tokenize import MWETokenizer

tokenizer = MWETokenizer([('20', '-', '30', 'minutes', 'a', 'day')])
tokenizer.tokenize(word_tokenize('Yes 20-30 minutes a day on my bike, it works great!!'))

[вне]:

['Yes', '20-30_minutes_a_day', 'on', 'my', 'bike', ',', 'it', 'works', 'great', '!', '!']

Более принципиальный подход, поскольку вы не знаете, как `word_tokenize разделит слова, которые вы хотите сохранить:

from nltk import word_tokenize
from nltk.tokenize import MWETokenizer

def multiword_tokenize(text, mwe):
    # Initialize the MWETokenizer
    protected_tuples = [word_tokenize(word) for word in mwe]
    protected_tuples_underscore = ['_'.join(word) for word in protected_tuples]
    tokenizer = MWETokenizer(protected_tuples)
    # Tokenize the text.
    tokenized_text = tokenizer.tokenize(word_tokenize(text))
    # Replace the underscored protected words with the original MWE
    for i, token in enumerate(tokenized_text):
        if token in protected_tuples_underscore:
            tokenized_text[i] = mwe[protected_tuples_underscore.index(token)]
    return tokenized_text

mwe = ['20-30 minutes a day', '!!']
print(multiword_tokenize('Yes 20-30 minutes a day on my bike, it works great!!', mwe))

[выход]:

['Yes', '20-30 minutes a day', 'on', 'my', 'bike', ',', 'it', 'works', 'great', '!!']
0 голосов
/ 10 апреля 2019

Насколько мне известно, вам будет трудно сохранить n-граммы различной длины одновременно с токенизацией, но вы можете найти эти n-граммы, как показано здесь . Затем вы можете заменить элементы в корпусе, которые вы хотите, в виде n-грамм на какой-нибудь присоединяющийся символ, например, тире.

Это пример решения, но, вероятно, есть много способов добраться до него. Важное замечание: Я предоставил способ найти нграммы, которые являются общими в тексте (вам, вероятно, понадобится больше 1, поэтому я поместил туда переменную, чтобы вы могли решить, сколько нграмм собрать. Вы могли бы хотеть различное число для каждого вида, но я пока дал только 1 переменную.) Это может пропустить ngram, которые вы считаете важными. Для этого вы можете добавить те, которые хотите найти, к user_grams. Они будут добавлены в поиск.

import nltk 

#an example corpus
corpus='''A big tantrum runs in my family 4x a day, every week. 
A big tantrum is lame. A big tantrum causes strife. It runs in my family 
because of our complicated history. Every week is a lot though. Every week
I dread the tantrum. Every week...Here is another ngram I like a lot'''.lower()

#tokenize the corpus
corpus_tokens = nltk.word_tokenize(corpus)

#create ngrams from n=2 to 5
bigrams = list(nltk.ngrams(corpus_tokens,2))
trigrams = list(nltk.ngrams(corpus_tokens,3))
fourgrams = list(nltk.ngrams(corpus_tokens,4))
fivegrams = list(nltk.ngrams(corpus_tokens,5))

В этом разделе приведены общие нграммы до пяти_грамм.

#if you change this to zero you will only get the user chosen ngrams
n_most_common=1 #how many of the most common n-grams do you want.

fdist_bigrams = nltk.FreqDist(bigrams).most_common(n_most_common) #n most common bigrams
fdist_trigrams = nltk.FreqDist(trigrams).most_common(n_most_common) #n most common trigrams
fdist_fourgrams = nltk.FreqDist(fourgrams).most_common(n_most_common) #n most common four grams
fdist_fivegrams = nltk.FreqDist(fivegrams).most_common(n_most_common) #n most common five grams

#concat the ngrams together
fdist_bigrams=[x[0][0]+' '+x[0][1] for x in fdist_bigrams]
fdist_trigrams=[x[0][0]+' '+x[0][1]+' '+x[0][2] for x in fdist_trigrams]
fdist_fourgrams=[x[0][0]+' '+x[0][1]+' '+x[0][2]+' '+x[0][3] for x in fdist_fourgrams]
fdist_fivegrams=[x[0][0]+' '+x[0][1]+' '+x[0][2]+' '+x[0][3]+' '+x[0][4]  for x in fdist_fivegrams]

#next 4 lines create a single list with important ngrams
n_grams=fdist_bigrams
n_grams.extend(fdist_trigrams)
n_grams.extend(fdist_fourgrams)
n_grams.extend(fdist_fivegrams)

В этом разделе вы можете добавить свои собственные нграммы в список

#Another option here would be to make your own list of the ones you want
#in this example I add some user ngrams to the ones found above
user_grams=['ngram1 I like', 'ngram 2', 'another ngram I like a lot']
user_grams=[x.lower() for x in user_grams]    

n_grams.extend(user_grams)

И эта последняя часть выполняет обработку, чтобы вы снова могли токенизироваться и получать нграммы как токены.

#initialize the corpus that will have combined ngrams
corpus_ngrams=corpus

#here we go through the ngrams we found and replace them in the corpus with
#version connected with dashes. That way we can find them when we tokenize.
for gram in n_grams:
    gram_r=gram.replace(' ','-')
    corpus_ngrams=corpus_ngrams.replace(gram, gram.replace(' ','-'))

#retokenize the new corpus so we can find the ngrams
corpus_ngrams_tokens= nltk.word_tokenize(corpus_ngrams)

print(corpus_ngrams_tokens)

Out: ['a-big-tantrum', 'runs-in-my-family', '4x', 'a', 'day', ',', 'every-week', '.', 'a-big-tantrum', 'is', 'lame', '.', 'a-big-tantrum', 'causes', 'strife', '.', 'it', 'runs-in-my-family', 'because', 'of', 'our', 'complicated', 'history', '.', 'every-week', 'is', 'a', 'lot', 'though', '.', 'every-week', 'i', 'dread', 'the', 'tantrum', '.', 'every-week', '...']

Я думаю, что это действительно очень хороший вопрос.

...