razdel
— библиотека для разделения русскоязычного текста на токены и предложения. Система построена на правилах.
>>> from razdel import tokenize
>>> tokens = list(tokenize('Кружка-термос на 0.5л (50/64 см³, 516;...)'))
>>> tokens
[Substring(0, 13, 'Кружка-термос'),
Substring(14, 16, 'на'),
Substring(17, 20, '0.5'),
Substring(20, 21, 'л'),
Substring(22, 23, '(')
...]
>>> [_.text for _ in tokens]
['Кружка-термос', 'на', '0.5', 'л', '(', '50/64', 'см³', ',', '516', ';', '...', ')']
>>> from razdel import sentenize
>>> text = '''
... - "Так в чем же дело?" - "Не ра-ду-ют".
... И т. д. и т. п. В общем, вся газета
... '''
>>> list(sentenize(text))
[Substring(1, 23, '- "Так в чем же дело?"'),
Substring(24, 40, '- "Не ра-ду-ют".'),
Substring(41, 56, 'И т. д. и т. п.'),
Substring(57, 76, 'В общем, вся газета')]
razdel
поддерживает Python 2.7+, 3.4+ и PyPy 2, 3.
$ pip install razdel
Важно! К сожалению, в задаче разделения текста на предложения и токены нет одного правильного ответа. Как, например, разбить на предложения текст "«Как же так?! Захар...» — воскликнут Пронин."? Можно считать, что это одно предложение, можно разбить на три "«Как же так?!", "Захар...»", "— воскликнут Пронин.", razdel
разобьёт на два "«Как же так?!", "Захар...» — воскликнут Пронин.". Как разделить на токены сокращение "т.е."? Можно считать, что это один токен, можно рабить на "т.", "е.", razdel
разобъёт на "т", ".", "е", ".".
razdel
старается разбивать текст на предложения и токены так, как это сделано в 4 датасетах: SynTagRus, OpenCorpora, ГИКРЯ и РНК из репозитория morphoRuEval-2017. В основном это новостные тексты и литература. Правила razdel
заточены под них. На текстах другой тематики (социальные сети, научные статьи) библиотека может работать хуже.
Мы считаем число ошибок, а не их долю, потому что в задаче токенизации очень много тривиальных тестов. Например, тест "чуть-чуть?!" нетривиальный, в нём токенизатор может ошибиться, дать ответ "чуть", "-", "чуть", "?", "!", хотя эталон "чуть-чуть", "?!", таких тестов мало. Большинство фраз простые, например для словосочетания "в 5 часов ...", правильный ответ даст даже str.split
: "в", "5", "часов", "...". Из-за тривиальных тестов качество всех систем получается высокое, тяжело оценить разницу между, например, "99.33%, 99.12%, 99.95%, 99.88%", поэтому мы пишем абсолютное число ошибок.
errors
— число ошибок, состоит из precision и recall-ошибок. Precision-ошибки считались так: возьмём все токены из разметки, например, "что-то", проверим, что токенизатор не делит их на части. Recall-ошибки считались так: возьмём все биграммы токенов, например, "что-то?", проверим, что разделение происходит между токенами, результат "что", "-", "то", "?" не считается recall-ошибкой, "то" и "?" разделены.
time
— время выполнения.
Что такое, например, spacy_tokenize
, spacy_tokenize2
написано в eval/zoo.py. Таблицы вычисляются в eval.ipynb
corpora | syntag | gicrya | rnc | |||||
---|---|---|---|---|---|---|---|---|
errors | time | errors | time | errors | time | errors | time | |
re.findall(\w+|\d+|\p+) | 1863 | 13.39 | 1613 | 14.74 | 1188 | 11.89 | 5005 | 12.64 |
nltk.word_tokenize | 1666 | 141.41 | 1685 | 146.76 | 169 | 106.38 | 1987 | 116.64 |
spacy_tokenize | 2846 | 73.26 | 2068 | 72.23 | 905 | 50.41 | 2706 | 51.05 |
spacy_tokenize2 | 2102 | 90.61 | 1272 | 89.12 | 226 | 63.28 | 1877 | 67.53 |
mystem | 2577 | 73.33 | 2137 | 72.51 | 1156 | 55.75 | 1297 | 57.73 |
moses | 1335 | 64.10 | 1405 | 65.34 | 808 | 49.13 | 1748 | 52.48 |
segtok.word_tokenize | 414 | 52.69 | 584 | 54.60 | 830 | 40.70 | 1252 | 39.18 |
razdel.tokenize | 348 | 27.99 | 460 | 28.36 | 151 | 21.22 | 1755 | 18.54 |
corpora | syntag | gicrya | rnc | |||||
---|---|---|---|---|---|---|---|---|
errors | time | errors | time | errors | time | errors | time | |
re.split([.?!…]) | 8027 | 10.19 | 2188 | 6.59 | 4096 | 7.79 | 8191 | 10.37 |
moses | 17131 | 73.15 | 8274 | 47.13 | 6698 | 55.79 | 21743 | 69.20 |
nltk.sent_tokenize | 7752 | 57.96 | 1907 | 34.52 | 2212 | 39.40 | 11390 | 49.64 |
segtok.split_single | 8981 | 79.18 | 1971 | 49.67 | 79135 | 13.92 | 86252 | 23.07 |
deepmipt | 4529 | 38.37 | 579 | 23.20 | 3502 | 26.86 | 7487 | 26.18 |
razdel.sentenize | 4323 | 26.75 | 369 | 16.09 | 5872 | 19.46 | 4903 | 19.56 |
MIT
- Чат — https://telegram.me/natural_language_processing
- Тикеты — https://github.com/natasha/razdel/issues
Тесты
pip install -e .
pip install -r requirements.txt
make test
make int # 2000 integration tests
Алиас ctl
source alias.sh
Посмотреть ошибки mystem
на syntag
cat data/syntag_tokens.txt | ctl sample 1000 | ctl gen | ctl diff --show moses_tokenize | less
Нетривиальные тесты для токенов
pv data/*_tokens.txt | ctl gen --recall | ctl diff space_tokenize > tests.txt
pv data/*_tokens.txt | ctl gen --precision | ctl diff re_tokenize >> tests.txt
Обновить интеграционные тесты
cd razdel/tests/data/
pv sents.txt | ctl up sentenize > t; mv t sents.txt
Посмотреть различия токенизации razdel
и moses
cat data/*_tokens.txt | ctl sample 1000 | ctl gen | ctl up tokenize | ctl diff moses_tokenize | less