Skip to content

Latest commit

 

History

History

site

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

ANYKS Smart language model

ANYKS Spell-checker (ASC) C++11

Описание проекта

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

Список возможностей

  • Исправление ошибок в словах с разницей до 4-х дистанций по Левенштейну.
  • Исправление опечаток в словах (вставка, удаление, замещение, перестановка) символов.
  • Ёфикация с учётом контекста.
  • Простановка регистра первой буквы слова, для (имён собственных и названий) с учётом контекста.
  • Разбиение объединённых слов на отдельные слова, с учётом контекста.
  • Выполнение анализа текста без корректировки исходного текста.
  • Поиск в тексте наличия (ошибок, опечаток, неверного контекста).

Зависимости

Сборка проекта

Python версия ASC

$ python3 -m pip install pybind11
$ python3 -m pip install anyks-sc

Документация pip

Клонирование проекта

$ git clone --recursive https://github.com/anyks/asc.git

Linux и FreeBSD

$ mkdir ./build
$ cd ./build

$ cmake ..
$ make

MacOS X

$ mkdir ./build
$ cd ./build

$ cmake -DOPENSSL_ROOT_DIR=/usr/local/Cellar/[email protected]/1.1.1g -DOPENSSL_LIBRARIES=/usr/local/Cellar/[email protected]/1.1.1g/include/lib ..
$ make

Готовые словари

Название Размер (Гб) Оперативная память (Гб) Размер N-грамм Язык
wittenbell-3-big.asc 1.97 15.6 3 RU
wittenbell-3-middle.asc 1.24 9.7 3 RU
mkneserney-3-middle.asc 1.33 9.7 3 RU
wittenbell-3-single.asc 0.772 5.14 3 RU
wittenbell-5-single.asc 1.37 10.7 5 RU

Тестирование

Для проверки работы системы, использовались данные соревнования «исправления опечаток» 2016 года от Dialog21. Для тестирования использовался обученный бинарный словарь: wittenbell-3-middle.asc

Precision Recall FMeasure
Режим исправления опечаток 76.97 62.71 69.11
Режим исправления ошибок 73.72 60.53 66.48

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

Материалы использовавшиеся в тестировании

  • test.txt - Текст для тестирования
  • correct.txt - Текст корректных вариантов
  • evaluate.py - Скрипт Python3 для расчёта результатов коррекции

Форматы файлов

Arpa

\data\
ngram 1=52
ngram 2=68
ngram 3=15

\1-grams:
-1.807052	1-й	-0.30103
-1.807052	2	-0.30103
-1.807052	3~4	-0.30103
-2.332414	как	-0.394770
-3.185530	после	-0.311249
-3.055896	того	-0.441649
-1.150508	</s>
-99	<s>	-0.3309932
-2.112406	<unk>
-1.807052	T358	-0.30103
-1.807052	VII	-0.30103
-1.503878	Грека	-0.39794
-1.807052	Греку	-0.30103
-1.62953	Ехал	-0.30103
...

\2-grams:
-0.29431	1-й передал
-0.29431	2 ложки
-0.29431	3~4 дня
-0.8407791	<s> Ехал
-1.328447	после того	-0.477121
...

\3-grams:
-0.09521468	рак на руке
-0.166590	после того как
...

\end\
N-грамма Встречаемость в корпусе Встречаемость в документах
только в одном 2 1

Vocab

\data\
ad=1
cw=23832
unq=9390

\words:
33	а	244 | 1 | 0.010238 | 0.000000 | -3.581616
34	б	11 | 1 | 0.000462 | 0.000000 | -6.680889
35	в	762 | 1 | 0.031974 | 0.000000 | -2.442838
40	ж	12 | 1 | 0.000504 | 0.000000 | -6.593878
330344	был	47 | 1 | 0.001972 | 0.000000 | -5.228637
335190	вам	17 | 1 | 0.000713 | 0.000000 | -6.245571
335192	дам	1 | 1 | 0.000042 | 0.000000 | -9.078785
335202	нам	22 | 1 | 0.000923 | 0.000000 | -5.987742
335206	сам	7 | 1 | 0.000294 | 0.000000 | -7.132874
335207	там	29 | 1 | 0.001217 | 0.000000 | -5.711489
2282019644	похожесть	1 | 1 | 0.000042 | 0.000000 | -9.078785
2282345502	новый	10 | 1 | 0.000420 | 0.000000 | -6.776199
2282416889	белый	2 | 1 | 0.000084 | 0.000000 | -8.385637
3009239976	гражданский	1 | 1 | 0.000042 | 0.000000 | -9.078785
3009763109	банкиры	1 | 1 | 0.000042 | 0.000000 | -9.078785
3013240091	геныч	1 | 1 | 0.000042 | 0.000000 | -9.078785
3014009989	преступлениях	1 | 1 | 0.000042 | 0.000000 | -9.078785
3015727462	тысяч	2 | 1 | 0.000084 | 0.000000 | -8.385637
3025113549	позаботьтесь	1 | 1 | 0.000042 | 0.000000 | -9.078785
3049820849	комментарием	1 | 1 | 0.000042 | 0.000000 | -9.078785
3061388599	компьютерная	1 | 1 | 0.000042 | 0.000000 | -9.078785
3063804798	шаблонов	1 | 1 | 0.000042 | 0.000000 | -9.078785
3071212736	завидной	1 | 1 | 0.000042 | 0.000000 | -9.078785
3074971025	холодной	1 | 1 | 0.000042 | 0.000000 | -9.078785
3075044360	выходной	1 | 1 | 0.000042 | 0.000000 | -9.078785
3123271427	делаешь	1 | 1 | 0.000042 | 0.000000 | -9.078785
3123322362	читаешь	1 | 1 | 0.000042 | 0.000000 | -9.078785
3126399411	готовится	1 | 1 | 0.000042 | 0.000000 | -9.078785
...
Идентификатор слова Слово Встречаемость в корпусе Встречаемость в документах tf tf-idf wltf
2282345502 новый 10 1 0.000420 0.000000 -6.776199

Описание:

  • ad - Общее количество документов в обучающем корпусе
  • cw - Общее количество слов в обучающем корпусе
  • oc - Встречаемость в корпусе
  • dc - Встречаемость в документах
  • tf - (term frequency — частота слова) — отношение числа вхождений некоторого слова к общему числу слов документа. Таким образом, оценивается важность слова в пределах отдельного документа, расчитывается как: [tf = oc / cw]
  • idf - (inverse document frequency — обратная частота документа) — инверсия частоты, с которой некоторое слово встречается в документах коллекции, расчитывается как: [idf = log(ad / dc)]
  • tf-idf - Расчитывается как: [tf-idf = tf * idf]
  • wltf - Рейтинг слова, расчитывается как: [wltf = 1 + log(tf * dc)]

Файл похожих букв в разных словарях

p  р
c  с
o  о
t  т
k  к
e  е
a  а
h  н
x  х
b  в
m  м
...
Искомая буква Разделитель Буква на замену
t \t т

Файл списка аббревиатур

г
р
США
ул
руб
рус
чел
...

Все слова из данного списка будут идентифицированны как неизвестное слово ⟨abbr⟩.

Файл списка доменных зон

ru
su
cc
net
com
org
info
...

Для более точного идентифицирования токена ⟨url⟩, следует добавить свои доменные зоны (все доменные зоны в примере, уже предустановлены).


Формат скрипта python предобработки полученных слов

# -*- coding: utf-8 -*-

def init():
    """
    Метод инициализации: выполняется только один раз при запуске приложения
    """

def run(word, context):
    """
    Метод запуска обработки: запускается при извлечении слова из текста
    @word    обрабатываемое слово
    @context последовательность предыдущих слов в виде массива
    """
    return word

Формат скрипта python определения собственных токенов слов

# -*- coding: utf-8 -*-

def init():
    """
    Метод инициализации: выполняется только один раз при запуске приложения
    """

def run(token, word):
    """
    Метод запуска обработки: запускается при извлечении слова из текста
    @token название токена слова
    @word  обрабатываемое слово
    """
    if token and (token == "<usa>"):
        if word and (word.lower() == "сша"): return "ok"
    elif token and (token == "<russia>"):
        if word and (word.lower() == "россия"): return "ok"
    return "no"

Пример скрипта python стемминга

import spacy
import pymorphy2

# Морфологический анализатор
morphRu = None
morphEn = None

def init():
    """
    Метод инициализации: выполняется только один раз при запуске приложения
    """
    # Получаем морфологический разбор
    global morphRu
    global morphEn
    # Активируем морфологический разбор для русского языка
    morphRu = pymorphy2.MorphAnalyzer()
    # Активируем морфологический разбор для английского языка
    morphEn = spacy.load('en', disable=['parser', 'ner'])

def eng(word):
    """
    Метод лемматизации английского языка
    @word слово для получения леммы
    """
    # Получаем морфологический разбор
    global morphEn
    # Получаем результат
    words = morphEn(word)
    # Получаем результат
    word = ''.join([token.lemma_ for token in words]).strip()
    # Если слово получено верное
    if word[0] != '-' and word[len(word) - 1] != '-':
        # Выводим результат
        return word
    else:
        # Выводим пустоту
        return ""

def rus(word):
    """
    Метод лемматизации русского языка
    @word слово для получения леммы
    """
    # Получаем морфологический разбор
    global morphRu
    # Если морфологический разбор активирован
    if morphRu != None:
        # Извлекаем результат
        word = morphRu.parse(word)[0].normal_form
        # Выводим результат
        return word
    else:
        # Выводим пустоту
        return ""

def run(word, lang):
    """
    Метод запуска морфологического разбора
    @word слово для получения леммы
    @lang язык алфавита передаваемого слова
    """
    # Если это русский язык
    if lang == "ru":
        # Выводим лемму для русского языка
        return rus(word.lower())
    # Если это английский язык
    elif lang == "en":
        # Выводим лемму для английского языка
        return eng(word.lower())

Переменные окружения

  • Все параметры можно передавать через переменные окружения. Переменные начинаются с префикса ASC_ и должны записываться в верхнем регистре, в остальном названия их соответствуют параметрам приложения.
  • Если одновременно указаны и параметры приложения и переменные окружения, приоритет будут иметь параметры приложения.
$ export ASC_R-ARPA=./lm.arpa

$ export ASC_R-BIN=./wittenbell-3-single.asc
  • Пример параметров в JSON формате
{
  "debug": 1,
  "method": "spell",
  "spell-verbose": true,
  "asc-split": true,
  "asc-alter": true,
  "asc-esplit": true,
  "asc-rsplit": true,
  "asc-uppers": true,
  "asc-hyphen": true,
  "asc-wordrep": true,
  "r-text": "./texts/input.txt",
  "w-text": "./texts/output.txt",
  "r-bin": "./dict/wittenbell-3-middle.asc"
}

Примеры

Пример работы программы

Информация о бинарном словаре

$ ./asc -method info -r-bin ./dict/wittenbell-3-middle.asc

Обучение

{
  "ext": "txt",
  "size": 3,
  "alter": {"е":"ё"},
  "debug": 1,
  "threads": 0,
  "method": "train",
  "vprune": true,
  "allow-unk": true,
  "reset-unk": true,
  "confidence": true,
  "interpolate": true,
  "mixed-dicts": true,
  "only-token-words": true,
  "kneserney-modified": true,
  "kneserney-prepares": true,
  "vprune-wltf": -15.0,
  "locale": "en_US.UTF-8",
  "smoothing": "mkneserney",
  "pilots": ["а","у","в","о","с","к","б","и","я","э","a","i","o","e","g"],
  "corpus": "./texts/corpus",
  "w-bin": "./dictionary/3-middle.asc",
  "w-abbr": "./dict/release/lm.abbr",
  "w-vocab": "./dict/release/lm.vocab",
  "w-arpa": "./dict/release/lm.arpa",
  "abbrs": "./texts/abbrs/abbrs.txt",
  "goodwords": "./texts/whitelist/words.txt",
  "badwords": "./texts/blacklist/words.txt",
  "alters": "./texts/alters/yoficator.txt",
  "upwords": "./texts/words/names/words",
  "mix-restwords": "./texts/similars/letters.txt",
  "alphabet": "абвгдеёжзийклмнопрстуфхцчшщъыьэюяabcdefghijklmnopqrstuvwxyz",
  "bin-code": "ru",
  "bin-name": "Russian",
  "bin-author": "You name",
  "bin-copyright": "You company LLC",
  "bin-contacts": "site: https://example.com, e-mail: [email protected]",
  "bin-lictype": "MIT",
  "bin-lictext": "... License text ...",
  "embedding-size": 28,
  "embedding": {
      "а": 0, "б": 1, "в": 2, "г": 3, "д": 4, "е": 5,
      "ё": 5, "ж": 6, "з": 7, "и": 8, "й": 8, "к": 9,
      "л": 10, "м": 11, "н": 12, "о": 0, "п": 13, "р": 14,
      "с": 15, "т": 16, "у": 17, "ф": 18, "х": 19, "ц": 20,
      "ч": 21, "ш": 21, "щ": 21, "ъ": 22, "ы": 23, "ь": 22,
      "э": 5, "ю": 24, "я": 25, "<": 26, ">": 26, "~": 26,
      "-": 26, "+": 26, "=": 26, "*": 26, "/": 26, ":": 26,
      "%": 26, "|": 26, "^": 26, "&": 26, "#": 26, "'": 26,
      "\\": 26, "0": 27, "1": 27, "2": 27, "3": 27, "4": 27,
      "5": 27, "6": 27, "7": 27, "8": 27, "9": 27, "a": 0,
      "b": 2, "c": 15, "d": 4, "e": 5, "f": 18, "g": 3,
      "h": 12, "i": 8, "j": 6, "k": 9, "l": 10, "m": 11,
      "n": 12, "o": 0, "p": 14, "q": 13, "r": 14, "s": 15,
      "t": 16, "u": 24, "v": 21, "w": 22, "x": 19, "y": 17, "z": 7
  }
}
$ ./asc -r-json ./train.json

Исправление ошибок

Чтение из файла текста -> исправление -> запись в новый файл исправленный текст

$ ./asc -debug 1 -method spell -spell-verbose -asc-split -asc-alter -asc-esplit -asc-rsplit -asc-uppers -asc-hyphen -asc-wordrep -r-text ./texts/input.txt -w-text ./texts/output.txt -r-bin ./dict/wittenbell-3-middle.asc

Чтение из потока -> исправление -> вывод в поток

$ echo "слзы теут на мрозе" | ./asc -debug 1 -method spell -spell-verbose -asc-split -asc-alter -asc-esplit -asc-rsplit -asc-uppers -asc-hyphen -asc-wordrep -r-bin ./dict/wittenbell-3-middle.asc

Работа в интерактивном режиме

$ ./asc -debug 1 -method spell -spell-verbose -asc-split -asc-alter -asc-esplit -asc-rsplit -asc-uppers -asc-hyphen -asc-wordrep -interactive -r-bin ./dict/wittenbell-3-middle.asc

Тоже работа с файлами, но через шаблон в формате JSON

{
  "debug": 1,
  "method": "spell",
  "spell-verbose": true,
  "asc-split": true,
  "asc-alter": true,
  "asc-esplit": true,
  "asc-rsplit": true,
  "asc-uppers": true,
  "asc-hyphen": true,
  "asc-wordrep": true,
  "r-text": "./texts/input.txt",
  "w-text": "./texts/output.txt",
  "r-bin": "./dict/wittenbell-3-middle.asc"
}
$ ./asc -r-json ./spell.json

Лицензия

MIT License

Приложение лицензируется под MIT License:

Авторские права © 2020 Лобарев Юрий

Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации (в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений, включая неограниченное право на использование, копирование, изменение, слияние, публикацию, распространение, сублицензирование и/или продажу копий Программного Обеспечения, а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:

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

ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ, СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ, ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ, ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.


Контакты

Если у вас есть вопросы относительно приложения, я бы хотел пригласить вас на GitHub. Пожалуйста, опишите ваш запрос, проблему или вопрос как можно более подробно, а также укажите версию библиотеки, которую вы используете, а также версию вашего компилятора и операционной системы. Открытие проблемы на GitHub позволяет другим пользователям и участникам этой библиотеки сотрудничать.


Лобарев Юрий [email protected]