Как я могу лемматизировать список списков в Python, используя spacy? - PullRequest
1 голос
/ 14 апреля 2019

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

Если я преобразую в строку, т. Е. nlp(str(list_1)), то разделители списка (такие как: "," и "[") будут размечены и включены в мой вывод.

Как я могу лемматизировать элементы в моем списке списков и вернуть его в ту же форму, то есть список списков?

Слова, которые нужно лемматизировать, могут быть где угодно в списке списков.

Я бы хотел что-то вроде этого:

Ввод:

[["flower", "grows", "garden"], [["boy", "running", "playground"]]

Выход:

[["flower", "grow", "garden"], ["boy", "run", "playground"]]

import spacy
nlp = spacy.load("en_core_web_sm")
list_1 = [["flower", "grows", "garden"], ["boy", "running", "playground"]]

for item in nlp(str(list_1)):
      print(item.lemma_)

Ответы [ 3 ]

2 голосов
/ 14 апреля 2019

Я бы разбил эту задачу на следующие части:

1. Создание объекта nlp и вашего текста

Вы уже сделали это, но для потомков:

nlp = spacy.load("en_core_web_sm")
words = [["flower", "grows", "garden"], ["boy", "running", "playground"]]

2. Получить длину каждого списка

Нам нужно иметь длину каждого списка, чтобы мы могли позже выполнить итерацию по нему (чтобы изменить выходные данные). Используя numpy.cumsum , мы можем создать массив, который позволит нам сделать это за O(n) время.

# remember about importing numpy
lengths = np.cumsum([0] + list(map(len, words)))
print(lengths)

Это даст нам следующий массив (для вашего случая):

[0 3 6]

Позже мы будем использовать диапазоны, созданные из этого массива, например, токены [0:3] составляют первый массив, а токены [3:6] составляют второй.

3. Сведите массив и создайте Doc

flat_words = [item for sublist in words for item in sublist]
doc = spacy.tokens.Doc(nlp.vocab, words=flat_words)

Лучше передать flat_words в виде списка, чтобы spacy не пришлось выполнять ненужную операцию токенизации.

4. Итерация по диапазонам

Наконец, итерируйте по spacy.tokens.Span объектам, по их токенам и добавляйте их (конечно, lemmatized) в список.

lemmatized = []
# Iterate starting with 1
for index in range(1, len(lengths)):
    # Slice doc as described in the first point, so [0:3] and [3:6]
    span = doc[lengths[index - 1] : lengths[index]]
    # Add lemmatized tokens as list to the outer list
    lemmatized.append([token.lemma_ for token in span])

Вывод print(lemmatized) будет таким, как вы хотели:

[['flower', 'grow', 'garden'], ['boy', 'run', 'playground']]

5. Весь код

Чтобы вам было проще, весь код ниже:

import numpy as np
import spacy

nlp = spacy.load("en_core_web_sm")
words = [["flower", "grows", "garden"], ["boy", "running", "playground"]]

lengths = np.cumsum([0] + list(map(len, words)))
print(lengths)


flat_words = [item for sublist in words for item in sublist]
doc = spacy.tokens.Doc(nlp.vocab, words=flat_words)

lemmatized = []
# Iterate starting with 1
for index in range(1, len(lengths)):
    # Slice doc as described in the first point, so [0:3] and [3:6]
    span = doc[lengths[index - 1] : lengths[index]]
    # Add lemmatized tokens as list to the list
    lemmatized.append([token.lemma_ for token in span])

print(lemmatized)
1 голос
/ 14 апреля 2019

Поскольку вы имеете дело со списком списков, вы можете объединить элементы в списках и затем использовать nlp().Затем получите лемму для каждого элемента в них.Чтобы снова получить списки списков, просто лемматизируйте элемент по индексу, в котором он находится.

for item in list_1:
    doc = nlp(' '.join(item))    
    for indexer,i in enumerate(doc):
        item[indexer] = i.lemma_
print(list_1)
#Output:
[['flower', 'grow', 'garden'], ['boy', 'run', 'playground']]
0 голосов
/ 14 апреля 2019

Не думаю, что это лучшее решение, но вы можете сделать это

import spacy
nlp = spacy.load("en_core_web_sm")
list_1 = [["flower", "grows", "garden"], ["boy", "running", "playground"]]

s=""
for item in nlp(str(list_1)):
      s+=item.lemma_
ss=s[2:-2].replace('\'','').split('],[')
l=[]
for sss in ss :
     l.append(sss.split(','))
print(l)

#output
[['flower', 'grow', 'garden'], ['boy', 'run', 'playground']]
...