Python (NLTK) - более эффективный способ извлечь существительные фразы?

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

Но мой настоящий вопрос заключается в том, изобретаю ли я здесь колесо? Есть ли более быстрый способ сделать это, чего я не вижу?

import nltk
import pandas as pd

myData = pd.read_excel("\User\train_.xlsx")
texts = myData['message']

# Defining a grammar & Parser
NP = "NP: {(<V\w+>|<NN\w?>)+.*<NN\w?>}"
chunkr = nltk.RegexpParser(NP)

tokens = [nltk.word_tokenize(i) for i in texts]

tag_list = [nltk.pos_tag(w) for w in tokens]

phrases = [chunkr.parse(sublist) for sublist in tag_list]

leaves = [[subtree.leaves() for subtree in tree.subtrees(filter = lambda t: t.label == 'NP')] for tree in phrases]

свести список списков кортежей, с которыми мы закончили, в список списков кортежей

leaves = [tupls for sublists in leaves for tupls in sublists]

Объедините извлеченные термины в один биграмм

nounphrases = [unigram[0][1]+' '+unigram[1][0] in leaves]

4 ответа

Решение

Посмотрите, почему моя функция NLTK работает медленно при обработке DataFrame? нет необходимости многократно повторять все строки, если вам не нужны промежуточные шаги.

С ne_chunk и решение от

[код]:

from nltk import word_tokenize, pos_tag, ne_chunk
from nltk import RegexpParser
from nltk import Tree
import pandas as pd

def get_continuous_chunks(text, chunk_func=ne_chunk):
    chunked = chunk_func(pos_tag(word_tokenize(text)))
    continuous_chunk = []
    current_chunk = []

    for subtree in chunked:
        if type(subtree) == Tree:
            current_chunk.append(" ".join([token for token, pos in subtree.leaves()]))
        elif current_chunk:
            named_entity = " ".join(current_chunk)
            if named_entity not in continuous_chunk:
                continuous_chunk.append(named_entity)
                current_chunk = []
        else:
            continue

    return continuous_chunk

df = pd.DataFrame({'text':['This is a foo, bar sentence with New York city.', 
                           'Another bar foo Washington DC thingy with Bruce Wayne.']})

df['text'].apply(lambda sent: get_continuous_chunks((sent)))

[из]:

0                   [New York]
1    [Washington, Bruce Wayne]
Name: text, dtype: object

Использовать кастом RegexpParser:

from nltk import word_tokenize, pos_tag, ne_chunk
from nltk import RegexpParser
from nltk import Tree
import pandas as pd

# Defining a grammar & Parser
NP = "NP: {(<V\w+>|<NN\w?>)+.*<NN\w?>}"
chunker = RegexpParser(NP)

def get_continuous_chunks(text, chunk_func=ne_chunk):
    chunked = chunk_func(pos_tag(word_tokenize(text)))
    continuous_chunk = []
    current_chunk = []

    for subtree in chunked:
        if type(subtree) == Tree:
            current_chunk.append(" ".join([token for token, pos in subtree.leaves()]))
        elif current_chunk:
            named_entity = " ".join(current_chunk)
            if named_entity not in continuous_chunk:
                continuous_chunk.append(named_entity)
                current_chunk = []
        else:
            continue

    return continuous_chunk


df = pd.DataFrame({'text':['This is a foo, bar sentence with New York city.', 
                           'Another bar foo Washington DC thingy with Bruce Wayne.']})


df['text'].apply(lambda sent: get_continuous_chunks(sent, chunker.parse))

[из]:

0                  [bar sentence, New York city]
1    [bar foo Washington DC thingy, Bruce Wayne]
Name: text, dtype: object

Я предлагаю обратиться к этой предыдущей теме: Извлечение всех существительных из текстового файла с помощью nltk

Они предлагают использовать TextBlob как самый простой способ добиться этого (если не самый эффективный с точки зрения обработки), и обсуждение там касается вашего вопроса.

from textblob import TextBlob
txt = """Natural language processing (NLP) is a field of computer science, artificial intelligence, and computational linguistics concerned with the interactions between computers and human (natural) languages."""
blob = TextBlob(txt)
print(blob.noun_phrases)

Вышеупомянутые методы не дали мне требуемых результатов. Ниже приведена функция, которую я бы предложил

      from nltk import word_tokenize, pos_tag, ne_chunk
from nltk import RegexpParser
from nltk import Tree
import re


def get_noun_phrases(text):
    pos = pos_tag(word_tokenize(text))
    count = 0
    half_chunk = ""
    for word, tag in pos:
        if re.match(r"NN.*", tag):
            count+=1
            if count>=1:
                half_chunk = half_chunk + word + " "
        else:
            half_chunk = half_chunk+"---"
            count = 0
    half_chunk = re.sub(r"-+","?",half_chunk).split("?")
    half_chunk = [x.strip() for x in half_chunk if x!=""]
    return half_chunk

Библиотека Constituent-Treelib , которую можно установить через:pip install constituent-treelibделает именно то, что вы ищете в нескольких строках кода. Чтобы извлечь именное (или любое другое) словосочетание, выполните следующие шаги.

      from constituent_treelib import ConstituentTree

# First, we have to provide a sentence that should be parsed
sentence = "I've got a machine learning task involving a large amount of text data."

# Then, we define the language that should be considered with respect to the underlying models 
language = ConstituentTree.Language.English

# You can also specify the desired model for the language ("Small" is selected by default)
spacy_model_size = ConstituentTree.SpacyModelSize.Medium

# Next, we must create the neccesary NLP pipeline. 
# If you wish, you can instruct the library to download and install the models automatically
nlp = ConstituentTree.create_pipeline(language, spacy_model_size) # , download_models=True

# Now, we can instantiate a ConstituentTree object and pass it the sentence and the NLP pipeline
tree = ConstituentTree(sentence, nlp)

# Finally, we can extract the phrases
tree.extract_all_phrases()

Результат...

      {'S': ["I 've got a machine learning task involving a large amount of text data ."],
 'PP': ['of text data'],
 'VP': ["'ve got a machine learning task involving a large amount of text data",
  'got a machine learning task involving a large amount of text data',
  'involving a large amount of text data'],
 'NML': ['machine learning'],
 'NP': ['a machine learning task involving a large amount of text data',
  'a machine learning task',
  'a large amount of text data',
  'a large amount',
  'text data']}

Если вам нужны только словосочетания с существительными, просто выберите их с помощьюtree.extract_all_phrases()['NP']

      ['a machine learning task involving a large amount of text data',
 'a machine learning task',
 'a large amount of text data',
 'a large amount',
 'text data']
Другие вопросы по тегам