Практические методики анализа текстовых данных с помощью Python
Методы анализа текстов на 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).