Данная статья представляет собой перевод главы, обучающей работе с текстовыми данными, из официальной документации scikit-learn. Начало статьи вы можете прочесть в части 1.

Обучение классификатора


Теперь, когда мы выделили признаки, можно обучать классификатор предсказывать категорию текста. Давайте начнем с Наивного Байесовского классификатора, который станет прекрасной отправной точкой для нашей задачи. scikit-learn включает в себя несколько вариантов этого классификатора. Самый подходящий для подсчета слов — это его поли номинальный вариант:

>>> from sklearn.naive_bayes import MultinomialNB
>>> clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)


Чтобы мы могли попытаться предсказать результаты на новом документе, нужно извлечь фичи (характерные признаки), используя почти такую же последовательность как и ранее. Разница состоит в том, используется метод transform вместо fit_transform из transformers, так как они уже были применены к нашей обучающей выборке:

>>> docs_new = ['God is love', 'OpenGL on the GPU is fast']
>>> X_new_counts = count_vect.transform(docs_new)
>>> X_new_tfidf = tfidf_transformer.transform(X_new_counts)

>>> predicted = clf.predict(X_new_tfidf)

>>> for doc, category in zip(docs_new, predicted):
...     print('%r => %s' % (doc, twenty_train.target_names[category]))
...
'God is love' => soc.religion.christian
'OpenGL on the GPU is fast' => comp.graphics


Создание конвейерной обработки


Чтобы с цепочкой vectorizer => transformer => classifier было проще работать, в scikit-learn есть класс Pipeline, который функционирует как составной (конвейерный) классификатор:

>>> from sklearn.pipeline import Pipeline
>>> text_clf = Pipeline([('vect', CountVectorizer()),
...                      ('tfidf', TfidfTransformer()),
...                      ('clf', MultinomialNB()),
... ])

Название vect, tfidf and clf (классификатор) выбраны нами произвольно. Мы рассмотрим их использование ниже, в главе grid search. Теперь обучим модель с помощью всего 1 команды:

>>> text_clf = text_clf.fit(twenty_train.data, twenty_train.target)


Оценка производительности при работе на тестовой выборке


Оценка точности прогноза модели достаточно проста:

>>> import numpy as np
>>> twenty_test = fetch_20newsgroups(subset='test',
...     categories=categories, shuffle=True, random_state=42)
>>> docs_test = twenty_test.data
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)            
0.834...

Например, мы получили 83% точности. Давайте посмотрим, можем ли мы улучшить этот результат с помощью линейного метода опорных векторов (support vector machine (SVM)). Этот метод обычно считается лучшим из алгоритмов классификации текста (хотя, он немного медленнее чем наивный Байес). Мы можем сменить обучающуюся модель просто подсоединив другой объект классификации в наш конвейер:

>>> from sklearn.linear_model import SGDClassifier
>>> text_clf = Pipeline([('vect', CountVectorizer()),
...                      ('tfidf', TfidfTransformer()),
...                      ('clf', SGDClassifier(loss='hinge', penalty='l2',
...                                            alpha=1e-3, n_iter=5, random_state=42)),
... ])
>>> _ = text_clf.fit(twenty_train.data, twenty_train.target)
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)            
0.912...

scikit-learn также предоставляет утилиты для более детального анализа результатов:

>>> from sklearn import metrics
>>> print(metrics.classification_report(twenty_test.target, predicted,
...     target_names=twenty_test.target_names))
...                                         
                        precision    recall  f1-score   support

           alt.atheism       0.95      0.81      0.87       319
         comp.graphics       0.88      0.97      0.92       389
               sci.med       0.94      0.90      0.92       396
soc.religion.christian       0.90      0.95      0.93       398

           avg / total       0.92      0.91      0.91      1502


>>> metrics.confusion_matrix(twenty_test.target, predicted)
array([[258,  11,  15,  35],
       [  4, 379,   3,   3],
       [  5,  33, 355,   3],
       [  5,  10,   4, 379]])

Как и ожидалось, матрица неточностей показывает, что тексты из выборки newsgroups об атеизме и христианстве модель чаще путает друг с другом, нежели чем с текстами про компьютерную графику.

Настройка параметров для использования grid search


Некоторые параметры мы уже посчитали, такие как use_idf в функции TfidfTransformer. Классификаторы, как правило, также имеют много параметров, например, MultinomialNB включает в себя коэффициент сглаживания alpha, а SGDClassifier имеет штрафной параметр alpha (метод штрафных функций), настраиваемую потерю и штрафные члены в целевой функции (см. раздел документации или используйте функцию подсказки Python, чтобы получить дополнительную информацию).
Вместо поиска параметров различных компонентов в цепи, можно запустить поиск (методом полного перебора ) лучших параметров в сетке возможных значений. Мы опробовали все классификаторы на словах или биграммах, с или без idf, с штрафными параметрами 0,01 и 0,001 для SVM (метода опорных векторов):

>>> from sklearn.grid_search import GridSearchCV
>>> parameters = {'vect__ngram_range': [(1, 1), (1, 2)],
...               'tfidf__use_idf': (True, False),
...               'clf__alpha': (1e-2, 1e-3),
... }

Очевидно, подобный поиск методом полного перебора может быть ресурсозатратным. Если в нашем распоряжении есть множество ядер процессора, мы можем запустить grid search, чтобы попробовать все комбинации параметров параллельно с параметром n_jobs. Если мы зададим этому параметру значение -1, grid search определит, как много ядер установлено, и задействует их все:

>>> gs_clf = GridSearchCV(text_clf, parameters, n_jobs=-1)

Экземпляр grid search ведет себя как обычная модель scikit-learn. Давайте запустим поиск на малой части обучающей выборки, чтобы увеличить скорость обработки:

>>> gs_clf = gs_clf.fit(twenty_train.data[:400], twenty_train.target[:400])

В результате применения метода fit на объекте GridSearchCV мы получим классификатор, который можно использовать для выполнения функции predict:

>>> twenty_train.target_names[gs_clf.predict(['God is love'])]
'soc.religion.christian'

но с другой стороны, это очень большой и громоздкий объект. Мы можем все таки получить оптимальные параметры, изучая атрибут объекта grid_scores_, который является списком пар параметры\мера. Чтобы получить атрибуты мер, мы можем:

>>> best_parameters, score, _ = max(gs_clf.grid_scores_, key=lambda x: x[1])
>>> for param_name in sorted(parameters.keys()):
...     print("%s: %r" % (param_name, best_parameters[param_name]))
...
clf__alpha: 0.001
tfidf__use_idf: True
vect__ngram_range: (1, 1)

>>> score                                              
0.900...

Упражнения


Чтобы выполнить упражнения, скопируйте содержание папки ‘skeletons’ в новую папку с названием ‘workspace’:

% cp -r skeletons workspace

ВЫ можете редактировать содержимое папки workspace, не боясь потерять исходные инструкции для упражнений.
Затем откройте оболочку ipython и запустите незавершенный скрипт для упражнения:

[1] %run workspace/exercise_XX_script.py arg1 arg2 arg3

Если было вызвано исключение, используйте %debug, чтобы запустить аварийную ipdb сессию.
Очистите реализацию и повторяйте, пока не решите задачу.
В каждом упражнении файлы skeleton содержат все необходимые инструкции импорта, шаблоны кода для загрузки данных и примеры для кода для оценки точности предсказывания модели.

Упражнения 1: Определение языка


  • Напишите конвейер — текстовый классификатор, используя специальную предобработку и CharNGramAnalyzer. В качестве обучающей выборки используйте статьи из Wikipedia.
  • Оцените производительность на любой тестовой выборке, не совпадающей с обучающей.

ipython командная строка:
%run workspace/exercise_01_language_train_model.py data/languages/paragraphs/


Упражнение 2: Анализ предпочтений на основе отзывов фильмов


  • Напишите конвейер — текстовый классификатор для классификации отзывов о фильмах на положительные и отрицательные.
  • Подберите подходящий набор параметров, используя grid search.
  • Оцените производительность на тестовой выборке.

ipython командная строка:
%run workspace/exercise_02_sentiment.py data/movie_reviews/txt_sentoken/


Упражнения 3: Утилита — текстовый классификатор в командной строке (консольное приложение)


Используя результаты предыдущих упражнений и модуль cPickle стандартной библиотеки, напишите утилиту командной строки, которая определяет язык текста в stdin (ввод с клавиатуры) и определяет полярность (положительный или отрицательный), если текст написан на английском.

Что дальше?


В этой секции приведены некоторые советы, чтобы помочь вам глубже познакомиться с scikit-learn после прохождения упражнений:

Комментарии (3)


  1. abiruba
    03.09.2015 13:40

    Спасибо. Хорошая работа.

    Сейчас занимаюсь изучением классификации коротких текстов. Подскажите на каком свете сейчас обстоит работа с русскими текстами у данного решения(да и вообще языками отличными от en)? Буду благодарен, если броситесь ссылками.


    1. Valr
      03.09.2015 17:19

      В scikit-learn нет тренировочных выборок на русском, методы лемматизации и стемминга не работают, токенизация проходит. Для этих целей можно использовать АОТ или SnowballStemmer. Последний не всегда хорошо справляется.


    1. Valr
      04.09.2015 11:01

      Кстати, если будете пробовать на русских текстах, то при загрузке обучающей \ тестовой выборки нужно это указать. Например, если вы создаете выборку типа 20 newsgroups:

      train_data = load_files(".../path/container_folder", encoding = "cp1251")