Я бы разбил эту задачу на следующие части:
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)