Сравнение распознавания сущностей русского языка в spaCy 2 и spaCy 3
В 2020 году для нового проекта мне потребовалось выбирать из текста названия компаний, имена людей, названия городов и т.п. По результатам гугления выяснилось, что речь идёт об “извлечении именованных сущностей” из текста (named entity recognition, NER). Для решения такой задачи существуют Python-библиотеки: nltk (10k звёзд), DeepPavlov (5k звёзд) и др. Но чаще всего встречался spaCy (20k звёзд). Сам spaCy на тот момент (v.2) не поддерживал русского языка из коробки, но к нему можно было подключить соответствующую модель через пакет Stanza (5k звёзд). Для справки, Stanza разрабатывается группой из Стэнфорда (The Stanford NLP Group). Ещё один способ подключения русского языка – использовать модель из пакетов natasha при помощи прослойки natasha-spacy (разработчик – Александр Кукушкин). Однако популярность у неё пониже, чем у Stanza.
В начале 2021 года вышел spaCy v.3. В нём появилась поддержка новых языков, включая русский. Причём, как я понял, законтрибутил его разработчик natasha. Есть три модели, отличающиеся размерами: ru_core_news_lg
, ru_core_news_md
, ru_core_news_sm
. Вместе со Stanza – 5 моделей для тестирования.
# spaCy 2.3.7 (stanza)
import stanza
from spacy_stanza import StanzaLanguage
import pandas as pd
import datetime
# Засекаем начало работы
start_ts = datetime.datetime.now().timestamp()
# stanza.download('ru')
# Подключаем stanza
snlp = stanza.Pipeline(lang='ru')
nlp = StanzaLanguage(snlp)
# Загружаем подготовленные новости
df = pd.read_csv('news.csv')
# Сюда будем складывать распознанные сущности
df2 = pd.DataFrame(columns=['id', 'entities'])
i = 0
for doc in nlp.pipe(df.text):
row_id = df.iloc[i]['id']
row_title = df.iloc[i]['title']
print('Document:', i, row_title)
entities = []
for ent in doc.ents:
entities.append((ent.text, ent.label_))
df2.loc[i] = {'id': row_id, 'entities': entities}
# Сохраняемся каждые 10 новостей и в конце
if (i % 10 == 0) or (i == len(df) - 1):
df2.to_csv('entities.csv', index=False)
i+=1
end_ts = datetime.datetime.now().timestamp()
print('Time, secs:', end_ts - start_ts)
# spaCy 3.0.6 (stanza)
-snlp = stanza.Pipeline(lang='ru')
-nlp = StanzaLanguage(snlp)
+nlp = spacy_stanza.load_pipeline('ru')
# spaCy 3.0.6
-snlp = stanza.Pipeline(lang='ru')
-nlp = StanzaLanguage(snlp)
+nlp = spacy.load('ru_core_news_lg')
Проходимся алгоритмами по 1000 новостей.
Среднее время работы:
v.2 (stanza) | v.3 (stanza) | v.3 lg | v.3 md | v.3 sm |
63.2 мин. | 58.5 мин. | 3.4 мин. | 3.3 мин. | 3.5 мин. |
Сразу замечаю, что spaCy обеих версий со Stanza выдаёт одинаковый результат по распознаванию. Ещё из таблицы видно, что алгоритмы со Stanza работают сильно дольше. Возможно, Stanza распознаёт больше сущностей и точнее? Решил изучить поглубже: взял 10 новостей разметил вручную и сравнил с алгоритмом. Да, тест на 10 новостях может показаться не показательным. Скорее всего так и есть. Но даже он занял день ручной работы.
По результатам, алгоритмы не всегда правильно распознали сущности и не все. Например:
Ручная разметка | Microsoft SQL Server | Windows 10 | МЧС России |
v.2.3.7 (stanza) | Microsoft SQL Server | Windows | МЧС России |
v.3.0.6 lg | Microsoft |
| МЧС, России (две сущности) |
v.3.0.6 md | Microsoft SQL Server |
| МЧС, России (две сущности) |
v.3.0.6 sm | Microsoft |
| МЧС, России (две сущности) |
Ошибки | Пропуски | |
v.2.3.7 (stanza) | 4,95% | 41,94% |
v.3.0.6 lg | 1,57% | 26,65% |
v.3.0.6 md | 2,05% | 27,17% |
v.3.0.6 sm | 1,39% | 28,55% |
Заметил, что:
spaCy со Stanza работает сильно дольше, но столь же большого различия в качестве работы я не заметил
точность распознавания зависит от текста: простой чёткий текст – точность выше
SpaCy 3 с родными моделями часто распознают сущности одинаково
есть ситуации, когда модели дополняют друг друга (одна нашла то, что не нашли другие)
есть ситуации, когда сам не знаешь, кто правее: ты или алгоритм
Выводы: если стоит задача получить статистическую информацию по большому числу текстов, я бы посмотрел в сторону spaCy 3 + ru_core_news_lg
. Если задача, из представленных алгоритмов со стандартными моделями достигнуть высокой точности, потребуются эвристики и модерирование.
P.S.: Дообучать модели я не пробовал – априори не знаю, какой бы это принесло результат.