Рубрики
Без рубрики

Python для НЛП: Маркировка частей речи и распознавание именованных сущностей

Автор оригинала: Usman Malik.

Это 4-я статья в моей серии статей по Python для НЛП. В моей предыдущей статье я объяснил , как библиотека space может использоваться для выполнения таких задач, как сопоставление слов и фраз.

В этой статье мы подробно рассмотрим части речевого тегирования и распознавания именованных сущностей. Мы увидим, как космическая библиотека может быть использована для выполнения этих двух задач.

Маркировка частей речи (POS)

Маркировка частей речи просто относится к присвоению частей речи отдельным словам в предложении, что означает, что, в отличие от сопоставления фраз, которое выполняется на уровне предложения или нескольких слов, маркировка частей речи выполняется на уровне токенов.

Давайте возьмем очень простой пример маркировки частей речи.

import spacy
sp = spacy.load('en_core_web_sm')

Как обычно, в приведенном выше скрипте мы импортируем основную модель space English. Затем нам нужно создать пространственный документ, который мы будем использовать для выполнения частей речи тегирования.

sen = sp(u"I like to play football. I hated it in my childhood though")

Объект документа пространства имеет несколько атрибутов, которые могут быть использованы для выполнения различных задач. Например, для печати текста документа используется атрибут text . Аналогично, атрибут pos_ возвращает крупнозернистый тег POS. Чтобы получить мелкозернистые POS-теги, мы могли бы использовать атрибут tag_ . И наконец, чтобы получить объяснение тега, мы можем использовать метод space.explain() и передать ему имя тега.

Давайте посмотрим на это в действии:

print(sen.text)

Приведенный выше скрипт просто печатает текст предложения. Вывод выглядит следующим образом:

I like to play football. I hated it in my childhood though

Далее рассмотрим атрибут pos_ . Мы напечатаем POS-тег слова “ненавистный”, который на самом деле является седьмым маркером в предложении.

print(sen[7].pos_)

Выход:

VERB

Вы можете видеть, что СООБЩЕНИЕ налоговых деклараций для “ненавистного” – это “ГЛАГОЛ”, поскольку “ненавистный” – это глагол.

Теперь давайте напечатаем мелкозернистый POS-тег для слова “ненавистный”.

print(sen[7].tag_)

Выход:

VBD

Чтобы увидеть, что означает VBD, мы можем использовать метод spacey.explain () , как показано ниже:

print(spacy.explain(sen[7].tag_))

Выход:

verb, past tense

Вывод показывает, что VBD-это глагол в прошедшем времени.

Давайте напечатаем текст, крупнозернистые POS-теги, мелкозернистые POS-теги и объяснение тегов для всех слов в предложении.

for word in sen:
    print(f'{word.text:{12}} {word.pos_:{10}} {word.tag_:{8}} {spacy.explain(word.tag_)}')

В приведенном выше сценарии мы улучшаем читаемость и форматирование, добавляя 12 пробелов между текстом и крупнозернистым POS-тегом, а затем еще 10 пробелов между крупнозернистыми POS-тегами и мелкозернистыми POS-тегами.

Выход:

I            PRON       PRP      pronoun, personal
like         VERB       VBP      verb, non-3rd person singular present
to           PART       TO       infinitival to
play         VERB       VB       verb, base form
football     NOUN       NN       noun, singular or mass
.            PUNCT      .        punctuation mark, sentence closer
I            PRON       PRP      pronoun, personal
hated        VERB       VBD      verb, past tense
it           PRON       PRP      pronoun, personal
in           ADP        IN       conjunction, subordinating or preposition
my           ADJ        PRP$     pronoun, possessive
childhood    NOUN       NN       noun, singular or mass
though       ADP        IN       conjunction, subordinating or preposition

Полный список тегов для частей речи и мелкозернистых тегов, а также их объяснение доступны в официальной документации space.

Почему POS-маркировка полезна?

POS-теги могут быть действительно полезны, особенно если у вас есть слова или токены, которые могут иметь несколько POS-тегов. Например, слово “google” может использоваться как существительное, так и глагол, в зависимости от контекста. При обработке естественного языка важно выявить это различие. К счастью, космическая библиотека поставляется предварительно построенной с алгоритмами машинного обучения, которые, в зависимости от контекста (окружающих слов), способны возвращать правильный POS-тег для слова.

Давайте посмотрим на это в действии. Выполните следующий сценарий:

sen = sp(u'Can you google it?')
word = sen[2]

print(f'{word.text:{12}} {word.pos_:{10}} {word.tag_:{8}} {spacy.explain(word.tag_)}')

В приведенном выше скрипте мы создаем космический документ с текстом “Can you google it?” Здесь слово “google” используется как глагол. Далее мы печатаем POS-тег для слова “google” вместе с объяснением тега. Вывод выглядит следующим образом:

google       VERB       VB       verb, base form

Из выходных данных вы можете видеть, что слово “google” было правильно идентифицировано как глагол.

Давайте теперь рассмотрим другой пример:

sen = sp(u'Can you search it on google?')
word = sen[5]

print(f'{word.text:{12}} {word.pos_:{10}} {word.tag_:{8}} {spacy.explain(word.tag_)}')

Здесь, в приведенном выше сценарии, слово “google” используется как существительное, как показано на выходе:

google       PROPN      NNP      noun, proper singular

Поиск количества POS-тегов

Вы можете найти количество вхождений каждого POS-тега, вызвав count_by в объекте space document. Метод принимает space.attrs.POS как значение параметра.

sen = sp(u"I like to play football. I hated it in my childhood though")

num_pos = sen.count_by(spacy.attrs.POS)
num_pos

Выход:

{96: 1, 99: 3, 84: 2, 83: 1, 91: 2, 93: 1, 94: 3}

В выходных данных вы можете увидеть идентификатор POS-тегов вместе с их частотами появления. Текст тега POS может быть отображен путем передачи идентификатора тега в словарь фактического документа пространства.

for k,v in sorted(num_pos.items()):
    print(f'{k}. {sen.vocab[k].text:{8}}: {v}')

Теперь в выходных данных вы увидите идентификатор, текст и частоту каждого тега, как показано ниже:

83. ADJ     : 1
84. ADP     : 2
91. NOUN    : 2
93. PART    : 1
94. PRON    : 3
96. PUNCT   : 1
99. VERB    : 3

Визуализация частей речевых тегов

Визуализация POS-тегов графическим способом чрезвычайно проста. Для этой цели используется модуль display из библиотеки space . Чтобы визуализировать POS-теги внутри блокнота Jupyter, вам нужно вызвать метод render из модуля displacy и передать ему документ spacy, стиль визуализации и установить атрибут jupyter в True как показано ниже:

from spacy import displacy

sen = sp(u"I like to play football. I hated it in my childhood though")
displacy.render(sen, style='dep', jupyter=True, options={'distance': 85})

В выходных данных вы должны увидеть следующее дерево зависимостей для POS-тегов.

Вы можете ясно видеть зависимость каждого токена от другого вместе с тегом POS.

Если вы хотите визуализировать POS-теги вне блокнота Jupyter, то вам нужно вызвать метод serve . График для POS-тегов будет напечатан в HTML-форме внутри вашего браузера по умолчанию. Выполните следующий сценарий:

displacy.serve(sen, style='dep', options={'distance': 120})

Как только вы выполните описанный выше сценарий, вы увидите следующее сообщение:

Serving on port 5000...
Using the 'dep' visualizer

Чтобы просмотреть дерево зависимостей, введите в браузере следующий адрес: http://127.0.0.1:5000/ . Вы увидите следующее дерево зависимостей:

Распознавание Именованных Сущностей

Распознавание именованных сущностей относится к идентификации слов в предложении как сущности, например, имени человека, места, организации и т. Д. Давайте посмотрим, как библиотека пространства выполняет распознавание именованных сущностей. Посмотрите на следующий сценарий:

import spacy
sp = spacy.load('en_core_web_sm')

sen = sp(u'Manchester United is looking to sign Harry Kane for $90 million')

В приведенном выше скрипте мы создали простой космический документ с некоторым текстом. Чтобы найти именованную сущность, мы можем использовать атрибут ents , который возвращает список всех именованных сущностей в документе.

print(sen.ents)

Выход:

(Manchester United, Harry Kane, $90 million)

Вы можете видеть, что были идентифицированы три названные сущности. Чтобы увидеть детали каждой именованной сущности, вы можете использовать метод text , label и метод space.explain , который принимает объект сущности в качестве параметра.

for entity in sen.ents:
    print(entity.text + ' - ' + entity.label_ + ' - ' + str(spacy.explain(entity.label_)))

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

Manchester United - ORG - Companies, agencies, institutions, etc.
Harry Kane - PERSON - People, including fictional
$90 million - MONEY - Monetary values, including unit

Вы можете видеть, что “Манчестер Юнайтед” был правильно идентифицирован как организация, компания и т. Д. Точно так же “Гарри Кейн” был идентифицирован как человек, и, наконец, “90 миллионов долларов” были правильно идентифицированы как сущность типа Денег.

Добавление Новых Сущностей

Вы также можете добавить новые сущности в существующий документ. Например, в следующем примере “Несфрута” не идентифицируется космической библиотекой как компания.

sen = sp(u'Nesfruita is setting up a new company in India')
for entity in sen.ents:
    print(entity.text + ' - ' + entity.label_ + ' - ' + str(spacy.explain(entity.label_)))

Выход:

India - GPE - Countries, cities, states

Из выходных данных вы можете видеть, что только Индия была идентифицирована как сущность.

Теперь, чтобы добавить “Nesfruita” как сущность типа “ORG” в наш документ, нам нужно выполнить следующие шаги:

from spacy.tokens import Span

ORG = sen.vocab.strings[u'ORG']
new_entity = Span(sen, 0, 1, label=ORG)
sen.ents = list(sen.ents) + [new_entity]

Во-первых, нам нужно импортировать класс Span из модуля space.tokens . Далее нам нужно получить хэш-значение типа сущности ORG из нашего документа. После этого нам нужно присвоить span хэш-значение ORG . Поскольку “Несфрута” – это первое слово в документе, интервал равен 0-1. Наконец, нам нужно добавить новый диапазон сущностей в список сущностей. Теперь, если вы выполните следующий скрипт, вы увидите “Nesfruta” в списке сущностей.

for entity in sen.ents:
    print(entity.text + ' - ' + entity.label_ + ' - ' + str(spacy.explain(entity.label_)))

Вывод приведенного выше скрипта выглядит следующим образом:

Nesfruita - ORG - Companies, agencies, institutions, etc.
India - GPE - Countries, cities, states

Подсчет Сущностей

В случае POS-тегов мы могли бы подсчитать частоту каждого POS-тега в документе с помощью специального метода can.count_by . Однако для именованных сущностей такого метода не существует. Мы можем вручную подсчитать частоту каждого типа сущностей. Предположим, что у нас есть следующий документ вместе с его сущностями:

sen = sp(u'Manchester United is looking to sign Harry Kane for $90 million. David demand 100 Million Dollars')
for entity in sen.ents:
    print(entity.text + ' - ' + entity.label_ + ' - ' + str(spacy.explain(entity.label_)))

Выход:

Manchester United - ORG - Companies, agencies, institutions, etc.
Harry Kane - PERSON - People, including fictional
$90 million - MONEY - Monetary values, including unit
David - PERSON - People, including fictional
100 Million Dollars - MONEY - Monetary values, including unit

Для подсчета сущностей типа person в приведенном выше документе мы можем использовать следующий скрипт:

len([ent for ent in sen.ents if ent.label_=='PERSON'])

В выходных данных вы увидите 2, так как в документе есть 2 сущности типа PERSON.

Визуализация Именованных Сущностей

Как и POS-теги, мы также можем просматривать именованные объекты внутри ноутбука Jupiter, а также в браузере.

Для этого мы снова будем использовать объект display . Посмотрите на следующий пример:

from spacy import displacy

sen = sp(u'Manchester United is looking to sign Harry Kane for $90 million. David demand 100 Million Dollars')
displacy.render(sen, style='ent', jupyter=True)

Вы можете видеть, что единственное различие между визуализацией именованных сущностей и POS-тегами заключается в том, что здесь в случае именованных сущностей мы передали ent в качестве значения параметра style . Вывод приведенного выше скрипта выглядит следующим образом:

Из выходных данных видно, что именованные сущности были выделены разными цветами вместе с их типами сущностей.

Вы также можете отфильтровать, какие типы сущностей будут отображаться. Для этого вам нужно передать тип сущностей для отображения в списке, который затем передается в качестве значения ключу ends словаря. Затем словарь передается в параметр options метода render модуля display , как показано ниже:

filter = {'ents': ['ORG']}
displacy.render(sen, style='ent', jupyter=True, options=filter)

В приведенном выше сценарии мы указали, что в выходных данных должны отображаться только сущности типа ORG. Вывод приведенного выше скрипта выглядит следующим образом:

Наконец, вы также можете отображать именованные сущности за пределами записной книжки Jupyter. Следующий сценарий отобразит именованные сущности в вашем браузере по умолчанию. Выполните следующий сценарий:

displacy.serve(sen, style='ent')

Теперь, если вы идете по адресу http://127.0.0.1:5000/ в вашем браузере вы должны увидеть именованные сущности.

Вывод

Части речи, помеченные тегами и распознавание именованных сущностей, имеют решающее значение для успеха любой задачи НЛП. В этой статье мы увидели, как космическая библиотека Python может быть использована для выполнения POS-тегов и распознавания именованных сущностей с помощью различных примеров.