Практические методики анализа текстовых данных с помощью Python

Раздел: Анализ данных -> NLP, частотный анализ

Методы анализа текстов на Python

Как выполнить комплексный анализ текста с очисткой, лемматизацией и частотным подсчётом с использованием spaCy?

Наиболее эффективное решение для русского языка включает библиотеку spaCy с предобученной моделью ru_core_news_sm. Процесс состоит из загрузки модели, чтения текста, лемматизации, удаления стоп-слов и небуквенных токенов, после чего подсчитывается частота слов с помощью Counter.

import spacy
from collections import Counter

nlp = spacy.load('ru_core_news_sm')
with open('text.txt', 'r', encoding='utf-8') as f:
    text = f.read()
doc = nlp(text)
tokens = [token.lemma_.lower() for token in doc if token.is_alpha and not token.is_stop]
freq = Counter(tokens)
for word, count in freq.most_common(10):
    print(f'{word}: {count}')

анализ текстов python (анализ текста на python)

Пояснения шагов: nlp = spacy.load(...) загружает модель. nlp(text) создаёт объект Doc с леммами и тегами. List comprehension фильтрует токены: is_alpha оставляет только буквенные, not token.is_stop исключает стоп-слова. lemma_.lower() приводит к нормальной форме в нижнем регистре. Counter формирует частотный словарь.

Типичные проблемы и ошибки

  • Модель не загружена: выполнить команду python -m spacy download ru_core_news_sm
  • Файл не найден или неправильная кодировка: указать полный путь к файлу и параметр encoding='utf-8'
  • Текст слишком большой для обработки за один раз: использовать генератор nlp.pipe(texts, batch_size=100) или разбить на части
  • Ошибка импорта spacy: установить библиотеку pip install spacy

Как быстро подсчитать количество слов в тексте без использования сложных NLP библиотек?

Для простого частотного анализа без лемматизации достаточно стандартных средств Python: модуль re и collections.Counter. Такой подход не требует установки дополнительных библиотек и работает быстро на небольших объёмах.

import re
from collections import Counter

with open('text.txt', 'r', encoding='utf-8') as f:
    text = f.read()

words = re.findall(r'\b\w+\b', text.lower())
freq = Counter(words)
print(freq.most_common(10))

Здесь регулярное выражение \b\w+\b находит последовательности букв, цифр и подчёркиваний. text.lower() приводит весь текст к нижнему регистру для единообразия. Counter(words) подсчитывает вхождения.

Возможные сложности

  • Слова с дефисами (например, «как-нибудь») разбиваются на две части. Для их сохранения измените шаблон: r'\b[\w-]+\b'
  • Числа и смешанные токены также попадают в результат. При необходимости используйте дополнительные фильтры
  • Крупные тексты могут потребовать много памяти – применяйте потоковую обработку

Как выделить наиболее значимые слова в документе относительно коллекции текстов с помощью TF-IDF?

Метод TF-IDF (Term Frequency – Inverse Document Frequency) позволяет оценить важность слова в конкретном документе среди набора документов. Реализация через TfidfVectorizer из библиотеки scikit-learn удобна и включает встроенный фильтр стоп-слов для русского языка.

from sklearn.feature_extraction.text import TfidfVectorizer

# Пример списка документов (можно загрузить из файлов)
docs = [
    'Москва столица России',
    'Санкт-Петербург культурная столица',
    'Россия большая страна'
]

vectorizer = TfidfVectorizer(max_features=100, stop_words='russian')
tfidf_matrix = vectorizer.fit_transform(docs)
feature_names = vectorizer.get_feature_names_out()

# Топ-5 слов для первого документа
first_doc_vector = tfidf_matrix[0].toarray()[0]
top_indices = first_doc_vector.argsort()[-5:][::-1]
print([feature_names[i] for i in top_indices])

Параметр max_features ограничивает количество слов, stop_words='russian' использует встроенный список стоп-слов. Для анализа конкретного документа берётся соответствующая строка матрицы, сортируются индексы по значению.

Ошибки при работе

  • Список стоп-слов может не подходить для конкретной задачи – загрузите свой через stop_words=list_of_words
  • Если документов мало (<10), IDF становится неустойчивым: лучше использовать max_df и min_df
  • Библиотека scikit-learn не установлена: pip install scikit-learn

Как применить стемминг для приведения слов к основе с помощью NLTK?

Стемминг (отсечение окончаний) – простой способ нормализации слов. Для русского языка подходит SnowballStemmer из NLTK. Он менее точен, чем лемматизация, но работает быстрее и не требует загрузки моделей.

import nltk
from nltk.stem.snowball import SnowballStemmer

nltk.download('punkt')  # для токенизации

stemmer = SnowballStemmer('russian')
words = ['человек', 'человека', 'люди', 'человечеству']
stems = [stemmer.stem(w) for w in words]
print(stems)  # ['человек', 'человек', 'люд', 'человечеств']

В реальном анализе сначала токенизируйте текст с помощью nltk.word_tokenize(text), затем примените стеммер к каждому токену.

Проблемы стемминга

  • Основа может быть не словом (например, «люд» вместо «люди»). Для более точной нормализации используйте лемматизацию (spaCy или pymorphy2)
  • Стемминг не учитывает контекст, из-за чего разные формы слов могут дать один стем, но могут и разные в зависимости от алгоритма
  • Пакет nltk.download('punkt') может не скачаться при отсутствии интернета: предварительно скачайте локально

Как визуализировать частотность слов в виде облака слов?

Облако слов (word cloud) наглядно показывает наиболее часто встречающиеся слова. Библиотека wordcloud позволяет создать его из словаря частот или напрямую из текста, с настройками цвета, фона и формы.

from wordcloud import WordCloud
import matplotlib.pyplot as plt

# freq – словарь вида {слово: частота} из предыдущих шагов
wc = WordCloud(width=800, height=400, background_color='white').generate_from_frequencies(freq)

plt.figure(figsize=(10, 5))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off')
plt.show()

Можно также передать исходный текст: .generate(text), но с предварительно очищенным списком слов результат будет точнее. Параметр max_words ограничивает количество отображаемых слов.

Типичные ошибки

  • Библиотека wordcloud не установлена: pip install wordcloud matplotlib
  • Слишком много слов делает облако нечитаемым – используйте max_words=100
  • Кириллица может отображаться кракозябрами: укажите шрифт с поддержкой кириллицы, например font_path='arial.ttf' (путь к шрифту на вашей системе)

Пример 1: Извлечение именованных сущностей (NER) с spaCy

NER позволяет находить в тексте имена людей, названия организаций, географические объекты и другие сущности. Модель ru_core_news_sm распознаёт несколько типов сущностей.

Пример
import spacy

nlp = spacy.load('ru_core_news_sm')
text = "Вчера в Москве состоялась встреча президента России и президента Франции Эммануэля Макрона."
doc = nlp(text)

print("Обнаруженные сущности:")
for ent in doc.ents:
    print(f"{ent.text} ({ent.label_})")
Обнаруженные сущности:
Москве (LOC)
России (LOC)
Франции (LOC)
Эммануэля Макрона (PER)

Типы сущностей: LOC – местоположение, PER – персона, ORG – организация, DATE – дата и др. Полный список доступен в документации spaCy.

Пример 2: Облако слов с маской изображения

Для создания облака в форме произвольного контура используется маска – чёрно-белое изображение, где белые области заполняются словами.

Пример
from wordcloud import WordCloud
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# загрузите маску (например, контур сердца)
mask = np.array(Image.open('heart_mask.png'))

# из предыдущего анализа имеем freq – словарь частот
wc = WordCloud(mask=mask, background_color='white', contour_color='darkred', contour_width=1)
wc.generate_from_frequencies(freq)

plt.figure(figsize=(6,6))
plt.imshow(wc, interpolation='bilinear')
plt.axis('off')
plt.show()

Результат – облако слов в форме сердца. Маску можно подготовить в любом графическом редакторе или найти готовые шаблоны.

Пример 3: Сравнение частотности лемм в двух документах

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

Пример
import spacy
from collections import Counter

def get_lemm_freq(filepath):
    nlp = spacy.load('ru_core_news_sm')
    with open(filepath, 'r', encoding='utf-8') as f:
        text = f.read()
    doc = nlp(text)
    tokens = [token.lemma_.lower() for token in doc if token.is_alpha and not token.is_stop]
    return Counter(tokens)

freq1 = get_lemm_freq('text1.txt')
freq2 = get_lemm_freq('text2.txt')

# общие слова, отсортированные по сумме частот
common_words = set(freq1.keys()) & set(freq2.keys())
sorted_common = sorted(common_words, key=lambda w: freq1[w]+freq2[w], reverse=True)[:10]

print("Топ-10 общих лемм (по суммарной частоте):")
for w in sorted_common:
    print(f"{w}: doc1={freq1[w]}, doc2={freq2[w]}")
Топ-10 общих лемм (по суммарной частоте):
сказать: doc1=45, doc2=32
делать: doc1=30, doc2=28
…

Пример 4: Частотный анализ биграмм (словосочетаний из двух слов)

Биграммы помогают выявить устойчивые выражения и коллокации. Реализация на основе spaCy и Counter.

Пример
import spacy
from collections import Counter

nlp = spacy.load('ru_core_news_sm')
text = "Москва является столицей России. Санкт-Петербург считается культурной столицей."
doc = nlp(text)

# извлекаем только слова (без знаков препинания)
tokens = [token.text.lower() for token in doc if token.is_alpha]

# формируем биграммы
bigrams = [f"{tokens[i]} {tokens[i+1]}" for i in range(len(tokens)-1)]
bigram_freq = Counter(bigrams)

print("Наиболее частые биграммы:")
for bg, cnt in bigram_freq.most_common(5):
    print(f"{bg}: {cnt}")
Наиболее частые биграммы:
является столицей: 1
столицей россии: 1
санкт-петербург считается: 1
считается культурной: 1
культурной столицей: 1

Для более содержательных результатов стоит удалять стоп-слова перед формированием биграмм, иначе частыми будут пары типа «в Москве», «на улице».

Пример 5: Анализ тональности с помощью готовой модели RuSentiment

RuSentiment – предобученная модель для русского языка на основе логистической регрессии. Используется библиотека dostoevsky.

Пример
# установка: pip install dostoevsky
from dostoevsky.tokenization import RegexTokenizer
from dostoevsky.models import FastTextSocialNetworkModel

tokenizer = RegexTokenizer()
model = FastTextSocialNetworkModel(tokenizer=tokenizer)

messages = [
    "Этот фильм просто замечательный! Очень понравился.",
    "Отвратительное обслуживание, больше не приду."
]

results = model.predict(messages, k=2)
for message, sentiment in zip(messages, results):
    print(f"Текст: {message}")
    print(f"Тональность: {sentiment}")  # {'positive': 0.98, 'negative': 0.02}
Текст: Этот фильм просто замечательный! Очень понравился.
Тональность: {'positive': 0.98, 'negative': 0.02}
Текст: Отвратительное обслуживание, больше не приду.
Тональность: {'positive': 0.01, 'negative': 0.99}

Модель возвращает вероятности для положительной и отрицательной тональности. Для использования убедитесь, что загружены данные (python -m dostoevsky download fasttext-social-network-model).

анализ текста на Python - comments

En
анализ текстов python (python)