Анализируем тексты Льва Толстого: как привести все слова к одному виду
easy

Анализируем тексты Льва Толстого: как привести все слова к одному виду

Нормально делаем — нормально получается

Продолжаем осваивать NLP — направление в программировании по работе с естественными языками. Проще говоря, учим компьютер разбирать текст на слова и работать с ними так, как нам нужно. В первой части мы сделали много интересного:

  • загрузили все тома «Войны и мира» в Python;
  • очистили текст от запятых, предлогов и переносов строк;
  • установили и настроили библиотеку NLTK для работы с текстом;
  • убрали из текста русские и французские стоп-слова (например, артикли и предлоги);
  • нашли самые частые слова в каждом томе;
  • нарисовали облако слов по популярности — чем чаще встречается слово, тем крупнее оно написано.

В чём проблема такого подхода

Во время обработки текста мы считали все слова по их количеству — сколько раз слово встречается в тексте. С этой точки зрения слова «который», «которая» и «которые» — это разные слова, хотя это одно слово, просто в разных лицах и числах.

С точки зрения частоты употребления такой подход не годится — он распыляет своё внимание на одинаковых по смыслу, но разных по написанию словах, поэтому облако слов получается неточным и разношёрстным.

Что мы сделаем: короткая версия

Чтобы каждое облако тегов максимально точно отражало суть происходящего в каждой книге, мы сделаем так:

  • приведём каждое слово в тексте к нормальной форме; 
  • построим новое облако слов для каждого тома;
  • найдём общие самые частые слова, которые есть в каждом томе;
  • уберём эти слова, если они есть в каждом облаке, чтобы они не мешали найти суть происходящего в книгах;
  • нарисуем новые облака слов, которые будут отражать уникальный сюжет каждой книги.

Зачем это всё?

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

Приводим слова в нормальную форму

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

# открываем текстовый файл
f = open('tom1.txt', "r", encoding="utf-8")
# закидываем его содержимое в переменную
text = f.read()
# выводим начало, чтобы убедиться, что всё считалось правильно
print(text[:300])
# переводим символы в нижний регистр, чтобы всё было одинаково
text = text.lower()
# подключаем встроенный модуль работы со строками
import string
# добавляем к стандартным знакам пунктуации кавычки и многоточие
spec_chars = string.punctuation + '«»\t—…’'
# очищаем текст от знаков препинания
text = "".join([ch for ch in text if ch not in spec_chars])
# подключаем регулярные выражения
import re
# меняем переносы строк на пробелы
text = re.sub('\n', ' ', text)
# убираем из текста цифры
text = "".join([ch for ch in text if ch not in string.digits])
# смотрим на результат
print(text[:300])
# из библиотеки обработки текста подключаем модуль для токенизации слов
from nltk import word_tokenize
# токенизируем текст
text_tokens = word_tokenize(text)
# подключаем библиотеку для работы с текстом
import nltk
# переводим токены в текстовый формат
# text = nltk.Text(text_tokens)
text = nltk.Text(text_tokens)
# подключаем статистику 
from nltk.probability import FreqDist
# и считаем слова в тексте по популярности
fdist = FreqDist(text)
# выводим первые 5 популярных слов
print(fdist.most_common(5))
# подключаем модуль со стоп-словами
from nltk.corpus import stopwords
# добавляем русские и французские стоп-слова
russian_stopwords = stopwords.words("russian")
russian_stopwords += stopwords.words("french")
# перестраиваем токены, не учитывая стоп-слова
text_tokens = [token.strip() for token in text_tokens if token not in russian_stopwords]
# снова приводим токены к текстовому виду
text = nltk.Text(text_tokens)
# считаем заново частоту слов
fdist_sw = FreqDist(text)
# показываем самые популярные
print(fdist_sw.most_common(10))
# добавляем свои слова в этот список
russian_stopwords.extend(['это', 'что','всё','сказал', 'сказала','говорил','говорила'])
# перестраиваем токены, не учитывая стоп-слова
text_tokens = [token.strip() for token in text_tokens if token not in russian_stopwords]
# снова приводим токены к текстовому виду
text = nltk.Text(text_tokens)
# считаем заново частоту слов
fdist_sw = FreqDist(text)
# показываем самые популярные
# подключаем библиотеку для создания облака слов
from wordcloud import WordCloud
# и графический модуль, с помощью которого нарисуем это облако
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt1
# переводим всё в текстовый формат
text_raw = " ".join(text)
# готовим размер картинки
wordcloud = WordCloud(width=1600, height=800).generate(text_raw)
plt.figure( figsize=(20,10), facecolor='k')
# добавляем туда облако слов
plt.imshow(wordcloud)
# выключаем оси и подписи
plt.axis("off")
# убираем рамку вокруг
plt.tight_layout(pad=0)
# выводим картинку на экран
plt.show()

Нормальная форма слова — это то, как оно записано в словаре:

  • для глаголов это будет неопределённая форма;
  • для существительных — единственное число, именительный падеж;
  • для прилагательных — единственное число, именительный падеж, мужской род.

После такой обработки слова «сказал», «сказали» и «скажут» превратятся в «сказать» — и у нас появится три одинаковых слова, вместо трёх разных. Для этого установим библиотеку с поддержкой русского языка pymorphy2:

pip install pymorphy2

Перед тем как продолжить, найдём в коде такую команду, чтобы добавить код после неё:

# токенизируем текст

text_tokens = word_tokenize(text)

Теперь подключаем библиотеку для нормализации и переводим все слова в нормальную форму:

# подключаем библиотеку для нормализации слов
import pymorphy2
# добавляем анализатор слов
morph = pymorphy2.MorphAnalyzer()
# тут будут те же самые слова, что и в исходном тексте, но в нормальной форме
filtered_tokens = []
# перебираем все слова в исходном тексте
for token in text_tokens:
    # получаем нормальную форму текущего слова
    p = morph.parse(str(token))[0]
    # добавляем его в новый массив
    filtered_tokens.append(p.normal_form)

Теперь нам нужно перевести в текстовый формат уже новые слова, поэтому меняем переменную в команде ниже:

# переводим токены в текстовый формат
text = nltk.Text(filtered_tokens)

И последнее, где нам нужно учесть работу с новой переменной, — это в перестройке токенов:

# перестраиваем токены, не учитывая стоп-слова
text_tokens = [token.strip() for token in filtered_tokens if token not in russian_stopwords]

Вот картинка для понимания, где именно нужно заменить в коде название переменной:

Сравниваем слова из четырёх томов

После запуска скрипта видно, что результат сильно отличается от того, что мы получили в первый раз: нормализация расставила всё по местам и показала настоящую частоту слов. 

Прогоним через скрипт все тома и посмотрим, есть ли в облаках одинаковые слова, которые забивают собой все остальные:

Первый
Второй
Третий
Четвёртый

Видно, что «который», «свой», «сказать» и «говорить» — самые частые слова в каждом томе. Это понятно: для Толстого это, по сути, служебные слова. Но если они есть везде, то, избавившись от них, мы получим более точное отражение того, что происходит в книгах.

У нас есть команда в скрипте, которая убирает ненужные слова из текста:

russian_stopwords.extend(['это', 'что','всё','сказал', 'сказала','говорил','говорила'])

Поменяем этот список и добавим в него такие слова:

  • который,
  • свой,
  • говорить,
  • сказать,
  • думать,
  • человек,
  • ещё,
  • весь.

Первый
Второй
Третий
Четвёртый

У нас проявились ещё несколько кандидатов для добавления в фильтр, которые перетягивают внимание на себя:

  • лицо,
  • время,
  • мочь,
  • знать,
  • видеть.

Добавим их в фильтр и запустим всё заново:

Первый
Второй
Третий
Четвёртый

Видно, что в первом томе мы знакомимся со всеми героями понемногу, потом фокусируемся вокруг злоключений Пьера и Наташи, далее в третьем томе наконец-то им составит компанию Наполеон. А в четвёртом томе главными героями снова станут Пьер и Наташа. Нет сомнений, что «Война и мир» гораздо больше про мир, чем про войну. 

Было → стало

Сравните сами две картинки: это слова из первого том без обработки и после анализа и добавления фильтров. В первой картинке всё внимание съели основные глаголы действия и «свой», а на второй видна суть книги.

Что дальше

То, что мы отобрали слова вручную, — иногда не самое лучшее решение. Гораздо круче было бы автоматически отфильтровать тексты так, чтобы в первой десятке популярных слов из каждого тома не было ни одного одинакового слова. Этим займёмся в следующий раз — нужно будет сильно кромсать и переделывать скрипт.

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Кирилл Климентьев

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Вам может быть интересно
easy
[anycomment]
Exit mobile version