2015-11-07 5 views
5

Есть ли более эффективный способ сделать это? Мой код читает текстовый файл и извлекает все существительные.Извлечение всех существительных из текстового файла с помощью nltk

import nltk 

File = open(fileName) #open file 
lines = File.read() #read all lines 
sentences = nltk.sent_tokenize(lines) #tokenize sentences 
nouns = [] #empty to array to hold all nouns 

for sentence in sentences: 
    for word,pos in nltk.pos_tag(nltk.word_tokenize(str(sentence))): 
     if (pos == 'NN' or pos == 'NNP' or pos == 'NNS' or pos == 'NNPS'): 
      nouns.append(word) 

Как уменьшить временную сложность этого кода? Есть ли способ избежать использования вложенных циклов?

Заранее благодарен!

+0

Замените условие if на 'if pos.startswith ('NN'):', также используйте 'set' или' collections.Counter', не сохраняйте список. И сделайте некоторую карту/сокращение вместо понимания списка. В противном случае попробуйте «мелкий разбор», ака 'chunking' – alvas

ответ

7

Если вы открыты для других опций, кроме 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 inter 
actions between computers and human (natural) languages.""" 
>>> blob = TextBlob(txt) 
>>> print(blob.noun_phrases) 
[u'natural language processing', 'nlp', u'computer science', u'artificial intelligence', u'computational linguistics'] 
+0

Вы говорите: «Он извлекает все существительные и существительные фразы легко», но я не вижу возможности извлекать только существительные. Как я мог получить имена в вашем примере, например «компьютер» или «наука»? – Sulli

+0

вы можете использовать 'blob.tags', чтобы отфильтровать' NN' только что-то вроде '[n для n, t в blob.tags, если t == 'NN']'. –

+0

Лично я обнаружил, что 'TextBlob' не работает почти так же, как' nltk' –

1

Я не эксперт по НЛП, но я думаю, что вы уже довольно близки, и здесь, вероятно, нет способа стать лучше, чем квадратичная сложность времени в этих внешних циклах.

В последних версиях NLTK есть встроенная функция, которая делает то, что вы делаете вручную, nltk.tag.pos_tag_sents, и она также возвращает список списков помеченных слов.

5
import nltk 

lines = 'lines is some string of words' 
# function to test if something is a noun 
is_noun = lambda pos: pos[:2] == 'NN' 
# do the nlp stuff 
tokenized = nltk.word_tokenize(lines) 
nouns = [word for (word, pos) in nltk.pos_tag(tokenized) if is_noun(pos)] 

print nouns 
>>> ['lines', 'string', 'words'] 

Полезного совет: это часто бывает, что списковые являются более быстрым способом построения списка, чем добавление элементов в список с .Применять() или добавить() метод, в пределах «для» петли ,

+0

Ответ правильный ход мыслей. Использование этого чище: 'is_noun = lambda pos: True if pos [: 2] == 'NN''. Примечание. Понимание списка не требуется быстрее, чем для цикла. Просто вам не нужно материализовывать список и обрабатывать вложенные циклы как генераторы вместо списка. – alvas

+0

@alvas - я не использовал что-то вроде '... pos [: 2] == 'NN' ...', потому что это могло бы совпадать с нежелательными строками. Насколько я знаю, может быть 'pos', который имеет значение« NNA », и мы не хотим его сопоставлять. Строго говоря, части «True if» и «else False» тоже не нужны, но я включил их для ясности. Хорошая точка зрения о том, что списки не обязательно быстрее, чем цикл (я думаю, что я был там близок) - я отредактировал сообщение соответственно. – Boa

+0

Просто из любопытства вы могли бы дать экземпляр «NNA»? Это так, что мы можем сделать некоторые проверки в NLTK по другим вопросам, не связанным с этим вопросом, хотя =). Технически не должно быть никаких тегов за пределами этого набора тегов: https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html – alvas

2

Ваш код не имеет избыточности: Вы читаете файл один раз и посетить каждое предложение, и каждый помеченный словом, ровно один раз. Независимо от того, как вы пишете свой код (например, с использованием понятий), вы будете скрывать только вложенные циклы, а не пропускать какую-либо обработку.

Единственный потенциал для улучшения - это сложность пространства: вместо того, чтобы сразу читать весь файл, вы можете читать его с шагом. Но поскольку вам нужно обрабатывать целые предложения за раз, это не так просто, как чтение и обработка одной строки за раз; поэтому я бы не стал беспокоиться, если ваши файлы не были целыми гигабайтами; для коротких файлов это не будет иметь никакого значения.

Короче говоря, ваши петли в порядке. В коде есть что-то или что-то, что вы могли бы очистить (например, предложение if, которое соответствует тегам POS), но это ничего не изменит с точки зрения эффективности.

Смежные вопросы