Почему существующие библиотеки неинтересны и как я создал лучшую.
Несколько месяцев назад мне понадобился способ обнаружения ненормативной лексики в отправленных пользователем текстовых строках:
В итоге я собрал и выпустил свою собственную библиотеку для этой цели под названием проверка на ненормативную лексику:
Конечно, прежде чем я это сделал, я поискал в Индексе пакетов Python (PyPI) любые существующие библиотеки, которые могли бы сделать это за меня. Единственными половинками достойных результатов по поисковому запросу ненормативная лексика были:
- Ненормативная лексика (идеальное название пакета)
- Better-profanity: Вдохновленная« ненормативной лексикой пакета Ben Friedland , эта библиотека намного быстрее оригинальной.»
- Profanityfilter (имеет 31 звезду Github, что на 30 больше, чем у большинства других результатов)
- Фильтр ненормативной лексики (использует машинное обучение, достаточно сказано ?!)
Однако сторонние библиотеки иногда могут быть отрывочными, поэтому я внимательно изучил эти 4 результата.
ненормативная лексика, улучшенная ненормативная лексика и фильтр ненормативной лексики
Быстро покопавшись в репозитории profanity
, я нашел файл с именем wordlist.txt:
Вся profanity
библиотека - всего лишь оболочка этого списка из 32 слов! profanity
обнаруживает ненормативную лексику, просто ища одно из этих слов.
К моему разочарованию, better-profanity
и profanityfilter
использовали один и тот же подход:
better-profanity
использует список из 140 словprofanityfilter
использует список слов из 418 слов
Это плохо, потому что библиотеки обнаружения ненормативной лексики на основе списков слов крайне субъективны. Например, в словарном списке better-profanity
есть слово «отстой». Вы готовы сказать, что любое предложение, содержащее слово «сосать», является оскорбительным? Более того, любой жестко закодированный список плохих слов неизбежно будет неполным - как вы думаете, 32 плохих слова profanity
единственные?
Исключив уже 3 библиотеки, я возлагаю надежды на 4-ю и последнюю: profanity-filter
.
фильтр ненормативной лексики
profanity-filter
использует машинное обучение! Милая!
Оказывается, это действительно медленно. Вот тест, который я провел в декабре 2018 года, сравнивая (1) profanity-filter
, (2) мою библиотеку profanity-check
и (3) profanity
(тот, который содержит список из 32 слов):
Мне нужно было иметь возможность делать много прогнозов в реальном времени, а profanity-filter
даже близко не подходил к этому. Но, может быть, это классический компромисс между точностью и скоростью, верно?
Неа.
Ни одна из библиотек, которые я нашел в PyPI, не соответствовала моим потребностям, поэтому я создал свою собственную.
Построение проверки на ненормативную лексику, часть 1: данные
Я знал, что хочу profanity-check
основывать свои классификации на данных, чтобы избежать субъективности (читай: чтобы иметь возможность сказать, что я использовал машинное обучение). Я собрал комбинированный набор данных из двух общедоступных источников:
- набор данных Twitter из t-davidson / hate-speech-and-offensive-language, который содержит твиты, взятые из Twitter.
- набор данных Wikipedia из this Kaggle Competition, опубликованный командой Alphabet Conversation AI, который содержит комментарии от правок страницы обсуждения Wikipedia.
Каждый из этих наборов данных содержит образцы текста, помеченные вручную людьми на краудсорсинговых сайтах, таких как Figure Eight.
Вот как в итоге выглядел мой набор данных:
В наборе данных Twitter есть столбец с именем
class
, в котором 0, если твит содержит язык вражды, 1, если он содержит оскорбительные выражения, и 2, если он не содержит ни того, ни другого. Я классифицировал любой твит сclass
из 2 как «Не оскорбительный», а все остальные твиты как «Оскорбительный».
В наборе данных Википедии есть несколько двоичных столбцов (например,
toxic
илиthreat
), которые показывают, содержит ли этот текст этот тип токсичности. Я классифицировал любой текст, содержащий любой из типов токсичности, как «Оскорбительный», а все другие тексты - как «Не оскорбительный».
Построение проверки на ненормативную лексику, часть 2: Обучение
Теперь, вооружившись очищенным комбинированным набором данных (который вы можете скачать здесь), я был готов обучать модель!
Я пропускаю процесс очистки набора данных, потому что, честно говоря, это довольно скучно - если вам интересно узнать больше о предварительной обработке текстовых наборов данных, ознакомьтесь с этим или этим.
Здесь происходит два основных этапа: (1) векторизация и (2) обучение.
Векторизация: мешок слов
Я использовал класс CountVectorizer scikit-learn
, который в основном превращает любую текстовую строку в вектор, подсчитывая, сколько раз встречается каждое данное слово. Это известно как представление Мешок слов (ЛУК). Например, если единственными словами на английском языке были the
, cat
, sat
и hat
, возможная векторизация предложения the cat sat in the hat
могла бы быть:
???
представляет любое неизвестное слово, которое в этом предложении равно in
. Любое предложение может быть представлено таким образом как количество the
, cat
, sat
, hat
и ???
!
Конечно, в английском языке гораздо больше слов, поэтому в приведенном выше коде я использую метод fit_transform()
, который выполняет две функции:
- Подгонка: запоминает словарный запас, просматривая все слова в наборе данных.
- Преобразовать: превращает каждую текстовую строку в наборе данных в векторную форму.
Обучение: линейный SVM
Я решил использовать модель Linear Support Vector Machine (SVM), которая реализована классом LinearSVC scikit-learn
. Это и это - хорошее введение, если вы не знаете, что такое SVM.
CalibratedClassifierCV в приведенном выше коде существует как оболочка, чтобы дать мне метод
predict_proba()
, который возвращает вероятность для каждого класса, а не просто классификацию. Однако вы можете просто проигнорировать это, если последнее предложение не имело для вас смысла.
Вот один (упрощенный) способ понять, почему работает линейная SVM: в процессе обучения модель узнает, какие слова «плохие», а какие «плохие», потому что эти слова чаще встречаются в оскорбительных текстах. Это как если бы процесс обучения подбирал для меня «плохие» слова, что намного лучше, чем использовать список слов, который я пишу сам!
Линейная SVM сочетает в себе лучшие аспекты других библиотек обнаружения ненормативной лексики, которые я обнаружил: она достаточно быстра, чтобы работать в режиме реального времени, но достаточно надежна, чтобы обрабатывать множество различных видов ненормативной лексики.
Предостережения
При этом profanity-check
далек от совершенства. Позвольте мне прояснить: относитесь к прогнозам profanity-check
с недоверием, потому что он делает ошибки. Например, плохо подбирать менее распространенные варианты ненормативной лексики, такие как «f4ck you» или «you b1tch», потому что они недостаточно часто встречаются в обучающих данных. Вы никогда не сможете обнаружить всю ненормативную лексику (люди будут изобретать новые способы обхода фильтров), но profanity-check
неплохо справляется с обнаружением большей части.
проверка ненормативной лексики
profanity-check
имеет открытый исходный код и доступен на PyPI! Чтобы использовать это, просто
$ pip install profanity-check
Как profanity-check
может быть еще лучше? Не стесняйтесь обращаться или комментировать любые мысли или предложения!
Также размещено на victorzhou.com.