Архив метки: классификация текстов

Классификация текстов методом Doc2vec в python

Используя любой метод классификации текстов, первоночально необходимо придумать способ перевода текстового документа в набор чисел. Ранее уже был рассмотрен метод на основе TF-IDF, в этот раз рассмотрим метод DOC2VEC. Из названия сразу понятно, что метод переводит документ в вектор, причём делается это просто. Сразу приведу код:

# определим датасет
some_texts = [
   'текст номер один',
   'Текст следуюйщих под номером два',
   'третий набор слов',
   'что-то ещё для полноценного дата-сета',
   'пример текстового документа'
]

from gensim.models.doc2vec import Doc2Vec, TaggedDocument
documents = [TaggedDocument(doc, [i]) for i, doc in enumerate(some_texts)]

model = Doc2Vec(documents, vector_size=5, workers=4, epochs=3)

Обучение, в данном примере (взятом из документации), происходит сразу при создании объекта. (Мне это показалось немного странным, после sklearn с методами fit и transform).
Некоторые основные параметры:
vector_size — какой конечный размер будет у вектора. Тонкий параметр, который придётся подбирать. Чем больше выборка и длиннее каждый документ — тем имеет смысл ставить параметр больше, порядка 100-300. Для небольших текстов и датасетов может хватить размерности 5-10.
epoch — кол-во эпох на обучении. Тоже потребует настройки, обычно 10-20

workers — сколько ядер хотите задействовать на обучении. (Узнать кол-во: from multiprocessing import cpu_count)
Стоит также отметить, что начальные веса для документов берутся случайно, и в дальнейшем происходит утряска-оптимизация весов. Поэтому после каждого обучения результирующий вектор для одного и того же документа будет разным.

Полезные методы Doc2Vec

# сохранение модели для дальнейшего использования
model.save("my_doc2vec_model")
# загрузка модели
model = Doc2Vec.load("my_doc2vec_model")
# нахождение наиболее похожего документа
vector_to_search = model.infer_vector(["ищем", "похожий", "текст"])
# три наиболее похожих
similar_documents = model.docvecs.most_similar([vector_to_search], topn=3)
for s in similar_documents:
    print(some_texts[s[0]])

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

from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()
clf.fit([model.infer_vector([x.words]) for x in documents], [1, 1, 1, 0, 0])
 
res = clf.predict([model.infer_vector(['текст', 'номер', 'три'])])
print(res)  # [1]

По своему опыту могу сказать, что doc2vec несколько капризная штука и по настоящему хорошо работать этот метод мне не удалось заставить. Особенно неприятно удивили результаты с находением наиболее похожих документов в датасете. Однако, т.к. это другой подход, отличный от классического bag of words, tf-idf а также от LDA и подходов на нейронных сетях, то можно его смело рекомендовать использовать в дополнение с другими алгоритмами для достижения максимальной точности классификации.

Простой пример классификации текста на python sklearn

Классификация текста — классическая задача в области обработки естественного языка. Лет 10-15 назад тема классификации бурлила в научных журналах, однако со временем бум утих. Это связоно с тем, что подход на основе TF-IDF показал точность близкую к 95%-99.9%. При такой точности на качество классификации больше уже влияют методы предобработки и особенности текста, чем непосредственно выбор самого алгоритма. Появление ембеддингов в 2013 году сильно повлияло на методы в обработке текстов, открыв новую эпоху. Сейчас практически все «production» решения основываются на ембеддингах, но! Тут надо сделать оговорку — ембеддинги чрезвычайно хороши для анализа коротких текстов, которыми сейчас полон интернет, а вот для средних и больших текстов — TF-IDF по прежнему на высоте!

Ниже я приведу базовый подход классификации на основе библиотеки sklearn в python. Код максимально короткий и понятный

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline


texts = ['текст номер один', 'текст номер два', 'комьютеры в лингвистике', 'компьютеры и обработка текстов']
texts_labels = [1, 1, 0, 0]

text_clf = Pipeline([
                     ('tfidf', TfidfVectorizer()),
                     ('clf', RandomForestClassifier())
                     ])

text_clf.fit(texts, texts_labels)

res = text_clf.predict(['текст номер три'])
print(res)  # [1]

На входе у нас список из текстов и список размеченных классов, далее делаем Pipeline, который включает в себя векторизацию слов на основе TfIdf и классификатор RandomForest . Далее обучаем «пайплайн-классификатор» и пытаемся предсказать новый текст. Как видим классификацию тексто на python сделать очень просто.

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

1. предобработка текста. Попробуйте нормализовать слова, тогда одно смысловое слово в разных склонениях/спряжениях будет интерпретироваться программой одинаково и возможно поднимет качество.
2. У TfIdf есть много разных параметров, наиболее существенные это
2.1 добавить список стоп слов: параметр stop_words
2.2 добавить n-gramm ы слов : параметр ngram_range, например ngram_range=(1,2)
2.3 ограничить список фич, взяв только самые важные и отрезав менее важные: параметр max_features
3. попробовать другой классификатор, например from sklearn.linear_model import SGDClassifier или SVM , XGB итд. соответсвенно подбирая в каждом из них свои гиперпараметры

С помощью перечисленных шагов, Вы достаточно быстро подберёте оптимальный вариант для классификации и получите точность более 90% (основываясь на моём опыте). Если не так, то возможно надо посмотреть внимательнее корректность входных данных.