Обработка текстовых данных на 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)
['Предложение первое.', 'А вот второе.', 'И третье.']

Полезно для разбиения документа на отдельные предложения перед дальнейшей обработкой.

обработка текстов на Python - comments

En
Python обработка текстов (python)