Обработка текстовых данных на Python: основные шаги анализа
Введение в обработку текстов
Анализ текста начинается с предобработки. Основные этапы: токенизация (разбиение на слова или предложения), очистка (удаление шума) и лемматизация (приведение к нормальной форме). В статье рассматриваются разные подходы с использованием библиотек и встроенных средств Python.
Основное решение: spaCy
Библиотека spaCy предлагает готовый пайплайн для токенизации, лемматизации и очистки с учётом языка. Она эффективна и проста в использовании.
import spacy
nlp = spacy.load("ru_core_news_sm")
text = "Автомобили мчались по шоссе, а дети играли во дворе."
doc = nlp(text)
tokens = [token.text for token in doc]
lemmas = [token.lemma_ for token in doc if not token.is_stop and not token.is_punct]
print(tokens)
print(lemmas)Python обработка текстов (обработка текстов на python)
['Автомобили', 'мчались', 'по', 'шоссе', ',', 'а', 'дети', 'играли', 'во', 'дворе', '.'] ['автомобиль', 'мчаться', 'шоссе', 'ребенок', 'играть', 'двор']
Проблемы: большая модель (около 50 МБ), требуется установка дополнительных компонентов. Для русского языка нужна модель ru_core_news_sm или ru_core_news_md. Возможны ошибки при обработке опечаток или нестандартных слов.
Как выполнить токенизацию без spaCy?
Для простых задач можно использовать NLTK или регулярные выражения.
import nltk
nltk.download('punkt')
from nltk.tokenize import word_tokenize
text = "Машины ехали быстро."
tokens = word_tokenize(text, language='russian')
print(tokens)['Машины', 'ехали', 'быстро', '.']
NLTK требует отдельной загрузки пунктуационной модели. При работе с нестандартными символами (эмодзи) может выдавать ошибки. Решение: предварительно очищать текст.
Цель: быстрая токенизация без зависимостей, когда точность не критична.
Как очистить текст от знаков препинания и цифр?
Регулярные выражения из модуля re позволяют гибко удалять ненужные символы.
import re
text = "Привет!!! Это тест 123."
cleaned = re.sub(r'[^a-zA-Zа-яА-ЯёЁ\s]', '', text)
print(cleaned)Привет Это тест
Удаляются все символы, кроме букв и пробелов. Если нужны точки или дефисы, шаблон корректируется. Проблема: могут остаться лишние пробелы. Решение: дополнительное сжатие через re.sub(' +', ' ', cleaned).strip().
Цель: удаление шума перед лемматизацией.
Как выполнить лемматизацию с pymorphy2?
Библиотека pymorphy2 предназначена для морфологического анализа русского языка.
import pymorphy2
morph = pymorphy2.MorphAnalyzer()
words = ['автомобили', 'играли', 'шоссе']
lemmas = [morph.parse(w)[0].normal_form for w in words]
print(lemmas)['автомобиль', 'играть', 'шоссе']
pymorphy2 может возвращать несколько вариантов разбора, берётся первый. При редких словах возможна ошибка. Требуется словарь (загружается автоматически).
Цель: лемматизация без spaCy, для русского языка.
Как объединить токенизацию, очистку и лемматизацию в один пайплайн?
Создание собственной функции с этапами.
def preprocess(text):
import re, pymorphy2
morph = pymorphy2.MorphAnalyzer()
text = text.lower()
text = re.sub(r'[^а-яё\s]', '', text)
tokens = text.split()
lemmas = [morph.parse(t)[0].normal_form for t in tokens if len(t) > 2]
return lemmas
print(preprocess('Автомобили мчались по шоссе!'))['автомобиль', 'мчаться', 'шоссе']
Проблема: порядок этапов важен. Сначала очистка, потом токенизация. Если удаление стоп-слов, то после лемматизации. Код не обрабатывает числа или эмодзи – требуется расширение.
Цель: полный контроль над процессом.
Как удалить стоп-слова из текста?
Стоп-слова – частые слова, не несущие смысла (предлоги, союзы).
import spacy
nlp = spacy.load("ru_core_news_sm")
doc = nlp("В лесу родилась ёлочка")
filtered = [token.text for token in doc if not token.is_stop]
print(filtered)['лесу', 'родилась', 'ёлочка']
Модель spaCy содержит встроенные стоп-слова. При использовании NLTK нужно загружать свой список. Возможны ложно‑положительные срабатывания (например, слово 'это' как стоп-слово в некоторых контекстах).
Цель: уменьшение размерности текста для дальнейшего анализа.
Расширенные примеры обработки текста
Дополнительные сценарии и нестандартные приёмы.
Пример 1: Пайплайн с поддержкой эмодзи и чисел
import re
import emoji
import pymorphy2
def advanced_preprocess(text):
# замена эмодзи на текстовые описания
text = emoji.demojize(text, delimiters=(' ', ' '))
# удаление хештегов и упоминаний (@)
text = re.sub(r'[#@][\w_]+', '', text)
# удаление URL
text = re.sub(r'https?://\S+', '', text)
# приведение к нижнему регистру
text = text.lower()
# оставить только буквы, цифры, пробелы (цифры не удалять)
text = re.sub(r'[^а-яёa-z0-9\s]', '', text)
# токенизация по пробелам
tokens = text.split()
morph = pymorphy2.MorphAnalyzer()
lemmas = []
for token in tokens:
if token.isdigit():
lemmas.append(token) # числа оставить как есть
else:
lemmas.append(morph.parse(token)[0].normal_form)
return lemmas
print(advanced_preprocess('Привет! ? Как дела? Смотри сайт https://example.com #новости'))['привет', 'улыбаться', 'дело', 'смотреть', 'сайт', 'новости']
Пояснение: эмодзи превращаются в слова (emoji.demojize), затем очищаются хештеги и ссылки. Числа сохраняются без лемматизации.
Пример 2: Сравнение стемминга и лемматизации
from nltk.stem import SnowballStemmer
import pymorphy2
stemmer = SnowballStemmer('russian')
morph = pymorphy2.MorphAnalyzer()
words = ['играет', 'играли', 'игровой']
for w in words:
print(f"{w}: stem - {stemmer.stem(w)}, lemma - {morph.parse(w)[0].normal_form}")играет: stem - игра, lemma - играть играли: stem - игра, lemma - играть игровой: stem - игр, lemma - игровой
Стемминг отрезает окончания, лемматизация возвращает словарную форму. Для русского языка лемматизация точнее.
Пример 3: Обработка большого текста построчно с использованием генератора
def tokenize_large_file(filepath):
import spacy
nlp = spacy.load('ru_core_news_sm', disable=['parser', 'ner'])
with open(filepath, 'r', encoding='utf-8') as f:
for line in f:
if line.strip():
doc = nlp(line)
tokens = [token.lemma_ for token in doc if not token.is_stop and not token.is_punct]
yield tokens
# пример использования:
for batch in tokenize_large_file('text.txt'):
print(batch[:10]) # первые 10 лемм каждой строкиПояснение: отключение ненужных компонентов (parser, ner) ускоряет обработку. Генератор не загружает весь файл в память.
Пример 4: Использование multiprocessing для параллельной обработки
import multiprocessing as mp
import spacy
def process_chunk(chunk):
nlp = spacy.load('ru_core_news_sm')
results = []
for text in chunk:
doc = nlp(text)
lemmas = ' '.join([token.lemma_ for token in doc if not token.is_stop])
results.append(lemmas)
return results
def parallel_preprocess(texts, num_processes=4):
chunk_size = len(texts) // num_processes
chunks = [texts[i:i+chunk_size] for i in range(0, len(texts), chunk_size)]
with mp.Pool(num_processes) as pool:
results = pool.map(process_chunk, chunks)
return [item for sublist in results for item in sublist]
texts = ["Текст один.", "Текст два."] * 1000
processed = parallel_preprocess(texts)
print(processed[:5])Пояснение: загрузка модели в каждом процессе, разделение текстов на чанки. Ускоряет работу на многоядерных процессорах.
Пример 5: Токенизация предложений с помощью NLTK
from nltk.tokenize import sent_tokenize
text = "Предложение первое. А вот второе. И третье."
sentences = sent_tokenize(text, language='russian')
print(sentences)['Предложение первое.', 'А вот второе.', 'И третье.']
Полезно для разбиения документа на отдельные предложения перед дальнейшей обработкой.