Шаг 185.
Введение в машинное обучение с использованием Python. Работа с текстовыми данными. ... . Модель "мешка слов" для киноотзывов

    На этом шаге мы рассмотрим использование "мешка слов" на конкретном примере.

    Теперь, когда мы детально разобрали процесс построения модели "мешка слов", давайте применим ее для анализа тональности киноотзывов. Ранее мы загрузили наши обучающие и тестовые данные, сформированные на основе отзывов IMDb, в виде списков строк (text_train и text_test) и сейчас обработаем их:

[In 12]:
vect = CountVectorizer().fit(text_train)
X_train = vect.transform(text_train)
print("X_train:\n{}".format(repr(X_train)))

X_train:
<75000x124255 sparse matrix of type '<class 'numpy.int64'>'
	with 10315542 stored elements in Compressed Sparse Row format>

    Матрица X_train соответствует обучающим данным, представленным в виде "мешка слов". Она имеет форму 75000x124255, указывая на то, что словарь включает 124255 элементов. Как видим, данные снова записаны в виде разреженной матрицы SciPy. Давайте более детально исследуем словарь. Еще один способ получить доступ к словарю - это использование метода get_feature_name(). Он возвращает удобный список, в котором каждый элемент соответствует одному признаку:

[In 13]:
feature_names = vect.get_feature_names()
print("Количество признаков: {}".format(len(feature_names)))
print("Первые 20 признаков:\n{}".format(feature_names[:20]))
print("Признаки с 20010 по 20030:\n{}".format(feature_names[20010:20030]))
print("Каждый 2000-й признак:\n{}".format(feature_names[::2000]))

Количество признаков: 124255
Первые 20 признаков:
['00', '000', '0000', '0000000000000000000000000000000001', '0000000000001', '000000001', 
'000000003', '00000001', '000001745', '00001', '0001', '00015', '0002', '0007', '00083', 
'000ft', '000s', '000th', '001', '002']
Признаки с 20010 по 20030:
['cheapen', 'cheapened', 'cheapening', 'cheapens', 'cheaper', 'cheapest', 'cheapie', 
'cheapies', 'cheapjack', 'cheaply', 'cheapness', 'cheapo', 'cheapozoid', 'cheapquels', 
'cheapskate', 'cheapskates', 'cheapy', 'chearator', 'cheat', 'cheata']
Каждый 2000-й признак:
['00', '_require_', 'aideed', 'announcement', 'asteroid', 'banquiere', 'besieged', 
'bollwood', 'btvs', 'carboni', 'chcialbym', 'clotheth', 'consecration', 'cringeful', 
'deadness', 'devagan', 'doberman', 'duvall', 'endocrine', 'existent', 'fetiches', 
'formatted', 'garard', 'godlie', 'gumshoe', 'heathen', 'honore', 'immatured', 'interested', 
'jewelry', 'kerchner', 'koln', 'leydon', 'lulu', 'mardjono', 'meistersinger', 'misspells', 
'mumblecore', 'ngah', 'oedpius', 'overwhelmingly', 'penned', 'pleading', 'previlage', 
'quashed', 'recreating', 'reverent', 'ruediger', 'sceme', 'settling', 'silveira', 
'soderberghian', 'stagestruck', 'subprime', 'tabloids', 'themself', 'tpf', 'tyzack', 
'unrestrained', 'videoed', 'weidler', 'worrisomely', 'zombified']

    Возможно, факт того, что первые 10 элементов словаря являются числами, немного удивителен. Все эти числа встречаются в отзывах и поэтому рассматриваются как слова. Большинство из этих чисел не имеют никакого смысла, за исключением числа "007", которое скорее всего связано с фильмами о Джеймсе Бонде.


Беглый анализ данных подтверждает, что это действительно так. Попробуйте самостоятельно убедиться в этом!

    Выделение значимой информации из незначимых "слов" является иногда довольно сложной задачей. Далее мы находим в словаре ряд английских слов, начинающихся с "dra". Можно заметить, что единственное число слов "draught", "drawback" и "drawer" обрабатывается отдельно от их множественного числа. Данные термины очень тесно связаны между собой по смыслу и обработка этих слов как разных, соответствующих различным признакам, не может быть оптимальным решением.

    Перед тем как мы пытаемся улучшить выделение признаков, давайте измерим качество модели, построив классификатор. У нас есть обучающие метки, хранящиеся в y_train и обучающие данные, представленные в виде "мешка слов" X_train, таким образом, мы можем обучить классификатор по этим данным. Как правило, для подобных высокоразмерных разреженных данных лучше всего работают линейные модели типа LogisticRegression.

    Давайте сначала применим LogisticRegression с использованием перекрестной проверки:


Вы, наверное, заметили, что в данном случае мы нарушаем принципы перекрестной проверки. На самом деле используя настройки, установленные для CountVectorizer по умолчанию, мы не собираем какие-либо статистики, поэтому наши результаты достоверны. Использование конвейера с самого начала было бы наилучшим выбором, но мы отложим его ради простоты.
[In 14]:
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
scores = cross_val_score(LogisticRegression(), X_train, y_train, cv=5)
print("Средняя правильность перекр проверки: {:.2f}".format(np.mean(scores)))

Средняя правильность перекр проверки: 0.85

    Мы получаем среднее значение правильности перекрестной проверки, равное 85%, что указывает на приемлемое качество модели для задачи сбалансированной бинарной классификации. Известно, что логистическая регрессия имеет параметр регуляризации C, который мы можем настроить с помощью перекрестной проверки:

[In 15]:
from sklearn.model_selection import GridSearchCV
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10]}
grid = GridSearchCV(LogisticRegression(), param_grid, cv=5)
grid.fit(X_train, y_train)
print("Наилучшее значение перекрестной проверки: {:.2f}".format(grid.best_score_))
print("Наилучшие параметры: ", grid.best_params_)

Наилучшее значение перекрестной проверки: 0.87
Наилучшие параметры: {'C': 0.1}

    Используя C=0.1, мы получаем значение перекрестной проверки 87%. Теперь мы можем оценить на тестовом наборе обобщающую способность при использовании данной настройки параметра:

[In 16]:
X_test = vect.transform(text_test)
print("Правильность на тестовом наборе: {:.2f}".format(grid.score(X_test, y_test)))

Правильность на тестовом наборе: 0.85

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг