Объект «список» не имеет атрибута «нижний» в синсетах wordnet

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

Сначала я преобразовал тег, заданный nltk.pos_tag, в тег, используемый wordnet.synsets, а затем по очереди применил .word_tokenize(), .pos_tag(), .synsets, как показано в следующем коде:

import numpy as np
import nltk
from nltk.corpus import wordnet as wn
import pandas as pd

#convert the tag to the one used by wordnet.synsets

def convert_tag(tag):    
    tag_dict = {'N': 'n', 'J': 'a', 'R': 'r', 'V': 'v'}
    try:
        return tag_dict[tag[0]]
    except KeyError:
        return None

#tokenize, tag, and find synsets (give the first match between each 'token' and 'word net_tag')

def doc_to_synsets(doc):

    token = nltk.word_tokenize(doc)
    tag = nltk.pos_tag(token)
    wordnet_tag = convert_tag(tag)
    syns = wn.synsets(token, wordnet_tag)

    return syns[0]

#test
doc = 'document is a test'
doc_to_synsets(doc)

который, если он запрограммирован правильно, должен возвращать что-то вроде

[Synset('document.n.01'), Synset('be.v.01'), Synset('test.n.01')]

Однако Python выдает сообщение об ошибке:

'list' object has no attribute 'lower'

Я также заметил, что в сообщении об ошибке говорится

lemma = lemma.lower()

Означает ли это, что мне также нужно «лемматизировать» мои токены как этот предыдущий поток подсказать? Или я должен применить .lower() к текстовому документу, прежде чем делать все это?

Я новичок в wordnet, на самом деле не знаю, вызывает ли проблема .synsets или виновата часть nltk. Будет очень признателен, если кто-то может просветить меня по этому поводу.

Спасибо.

[Изменить] трассировка ошибок

AttributeError                            Traceback (most recent call last)
<ipython-input-49-5bb011808dce> in <module>()
     22     return syns
     23 
---> 24 doc_to_synsets('document is a test.')
     25 
     26 

<ipython-input-49-5bb011808dce> in doc_to_synsets(doc)
     18     tag = nltk.pos_tag(token)
     19     wordnet_tag = convert_tag(tag)
---> 20     syns = wn.synsets(token, wordnet_tag)
     21 
     22     return syns

/opt/conda/lib/python3.6/site-packages/nltk/corpus/reader/wordnet.py in synsets(self, lemma, pos, lang, check_exceptions)
   1481         of that language will be returned.
   1482         """
-> 1483         lemma = lemma.lower()
   1484 
   1485         if lang == 'eng':

AttributeError: 'list' object has no attribute 'lower'

Итак, после использования кода, любезно предложенного @dugup и $udiboy1209, я получаю следующий вывод:

[[Synset('document.n.01'),
  Synset('document.n.02'),
  Synset('document.n.03'),
  Synset('text_file.n.01'),
  Synset('document.v.01'),
  Synset('document.v.02')],
 [Synset('be.v.01'),
  Synset('be.v.02'),
  Synset('be.v.03'),
  Synset('exist.v.01'),
  Synset('be.v.05'),
  Synset('equal.v.01'),
  Synset('constitute.v.01'),
  Synset('be.v.08'),
  Synset('embody.v.02'),
  Synset('be.v.10'),
  Synset('be.v.11'),
  Synset('be.v.12'),
  Synset('cost.v.01')],
 [Synset('angstrom.n.01'),
  Synset('vitamin_a.n.01'),
  Synset('deoxyadenosine_monophosphate.n.01'),
  Synset('adenine.n.01'),
  Synset('ampere.n.02'),
  Synset('a.n.06'),
  Synset('a.n.07')],
 [Synset('trial.n.02'),
  Synset('test.n.02'),
  Synset('examination.n.02'),
  Synset('test.n.04'),
  Synset('test.n.05'),
  Synset('test.n.06'),
  Synset('test.v.01'),
  Synset('screen.v.01'),
  Synset('quiz.v.01'),
  Synset('test.v.04'),
  Synset('test.v.05'),
  Synset('test.v.06'),
  Synset('test.v.07')],
 []]

Теперь проблема сводится к извлечению первого совпадения (или первого элемента) каждого списка из списка «syns» и превращению их в новый список. Для пробного документа «документ является тестом» он должен возвращать:

[Synset('document.n.01'), Synset('be.v.01'), Synset('angstrom.n.01'), Synset('trial.n.02')]

который представляет собой список первого совпадения для каждого токена в текстовом документе.


person Chris T.    schedule 29.08.2017    source источник
comment
Можете ли вы опубликовать всю трассировку ошибок?   -  person Tony    schedule 29.08.2017
comment
Я включил это в часть «редактировать» под исходным сообщением.   -  person Chris T.    schedule 29.08.2017
comment
Почему вы используете .lower()?   -  person RulerOfTheWorld    schedule 29.08.2017
comment
Я не использовал .lower() в своем коде, но видел, что это упоминалось в паре предыдущих веток вопросов, поэтому я поднял здесь.   -  person Chris T.    schedule 29.08.2017
comment
@ChrisT какой результат кода, если перед строкой lemma = lemma.lower() поставить print(lemma)   -  person RulerOfTheWorld    schedule 29.08.2017
comment
Извините, мне нужно пойти по делам, я не понял вашу проблему, поэтому я займусь этим снова через час, если никто другой не добрался до этого. @RulerOfTheWorld, Крис немного неправильно использует NLTK, вызывая предупреждение внутри этого пакета. Он не звонит ниже.   -  person Tony    schedule 29.08.2017
comment
Этого нет в моем коде, и мне интересно, почему lemma.lower() (или что-то, что связано с «леммой») появилось в сообщении об ошибке.   -  person Chris T.    schedule 29.08.2017
comment
@Tony, еще раз спасибо за помощь! Я также пересмотрю свою исходную тему, так как «возьмите 1-ю» выглядит вводящей в заблуждение.   -  person Chris T.    schedule 29.08.2017
comment
@ Тони хорошо, спасибо, что прояснил это :)   -  person RulerOfTheWorld    schedule 29.08.2017


Ответы (2)


Проблема в том, что wn.synsets ожидает один токен в качестве первого аргумента, но word_tokenize возвращает список, содержащий все токены в документе. Таким образом, ваши переменные token и tag на самом деле являются списками.

Вам нужно перебрать все пары токен-тег в вашем документе и сгенерировать синсет для каждого отдельно, используя что-то вроде:

tokens = nltk.word_tokenize(doc)
tags = nltk.pos_tag(tokens)
doc_synsets = []
for token, tag in zip(tokens, tags):
    wordnet_tag = convert_tag(tag)
    syns = wn.synsets(token, wordnet_tag)
    # only add the first matching synset to results
    doc_synsets.append(syns[0])
person dugup    schedule 29.08.2017
comment
Спасибо за ответ. Я попробовал вашу рекомендацию, она сгенерировала тот же результат, что и код @ udiboy1209. Итак, как я могу извлечь первое совпадение каждого токена из документа и создать вывод, подобный этому (это то, что я получил, используя ваш код): [Synset('document.n.01'), Synset('be. v.01'), Synset('angstrom.n.01'), Synset('trial.n.02')] - person Chris T.; 29.08.2017
comment
Что именно вы подразумеваете под первым совпадением каждого токена? syns — это список, содержащий все синонимы из wordnet для данного токена — вы можете добавить первый элемент к результатам вместо всего списка с помощью all_synsets.append(syns[0]) - person dugup; 30.08.2017
comment
syns возвращает список «список ссылок nltk» для каждого токена, которые являются потенциальными совпадениями между этим токеном и wordnet_tag. Если у вас есть 5 токенов в текстовом документе, он вернет 5 списков ссылок для этих 5 токенов. Использование «all_synsets.append(syns[0])» возвращает только список ссылок для первого токена. Я хочу получить первое совпадение между каждым токеном и wordnet_tag для всех токенов в текстовом документе. Таким образом, вывод должен выглядеть так: [Synset('document.n.01'), Synset('be.v.01'), Synset('test.n.01')] - person Chris T.; 30.08.2017
comment
Я использовал first_match = [x[0] for x в doc_to_synsets('document is a test.')] для получения списка первых совпадений для каждого токена в документе, но Python возвращает сообщение об ошибке 'list index out of range. ' Я смущен. - person Chris T.; 30.08.2017
comment
Я обновил свой ответ, добавив к результатам первый синсет для каждого токена. В конце цикла doc_synsets будет список, содержащий первое совпадение для каждого токена в документе, и он должен быть тем, что вы хотите. - person dugup; 30.08.2017
comment
Вывод такой же, как и ваша предыдущая рекомендация, и теперь он не подлежит подписке. - person Chris T.; 30.08.2017
comment
Я предполагаю, что теперь вопрос сводится к (1) получению первого элемента из списка списка (т. Е. Syns) и (2) превращению этих «первых элементов» в новый список. Например, «документ является тестом» имеет 4 токена, поэтому желаемый результат должен иметь вид [syns[0][0], syns[1][0], syns[2][0], syns[0]. ][3]]. Я пытался пройти через вывод «syns», но продолжал получать ошибку «индекс списка вне диапазона». - person Chris T.; 30.08.2017
comment
Я добавил вывод syns внизу моего исходного вопроса, так легче визуализировать желаемый формат вывода. - person Chris T.; 30.08.2017

lower() — это функция типа str, которая в основном возвращает строчную версию строки.

Похоже, что nltk.word_tokenize() возвращает список слов, и ни единого слова. Но для synsets() вам нужно передать одну строку, а не список строк.

Вы можете попробовать запустить synsets в цикле следующим образом:

for token in nltk.word_tokenize(doc):
    syn = wn.synsets(token)

РЕДАКТИРОВАТЬ: лучше использовать понимание списка, чтобы получить список синхов

syns = [wn.synsets(token) for token in nltk.word_tokenize(doc)]
person udiboy1209    schedule 29.08.2017