Экспериментирую с ML. Несколько недель ковыряюсь в данных и всё больше понимаю — алгоритмы это не главное. Главная боль — подготовка данных.
Уже несколько недель разбираюсь с машинным обучением. Не ради статьи на Смартлабе — захотелось понять, как это устроено изнутри. И чем глубже погружаюсь, тем больше понимаю: вся «магия» моделей начинается задолго до самого обучения.
Собрать данные — не проблема. Подготовить их — проблема. И особенно сложно — сбалансировать классы.
Когда модель учится отличать категории, она должна видеть их примерно в равных долях. Если один класс встречается гораздо чаще других, модель быстро «разучивается думать» и начинает просто угадывать самый частый вариант. В итоге вроде бы всё обучилось, но результат — в мусорку.
На практике это выглядит так:
- один класс (нейтральный) встречается чуть ли не в половине всех примеров,
- другие (позитивный и негативный) — заметно реже,
- при этом удалить лишние примеры нельзя вслепую — можно потерять важный контекст и сместить распределение признаков.
После долгих экспериментов и отбраковки однотипных записей я получил такую картину:

Выглядит вроде бы прилично, но за этими цифрами — десятки вариантов фильтрации, пересемплирования и чистки.
Главная проблема — нейтральные примеры. Их очень много, и именно они чаще всего «смазывают» сигналы в данных.
Удалить слишком много — модель потеряет способность видеть естественные переходные состояния.
Удалить слишком мало — она начнёт всё считать нейтральным.
Это в продолжение темы.
Поэтому подбор баланса — это не механическая операция, а прямо сложно.
Ведь машинное обучение — это не про «нажал кнопку и получил результат» как в ChatGPT. Это скорее про методичное, почти исследовательское выравнивание весов, классов и смыслов.
Если кто-то тоже бьётся с дисбалансом классов — делитесь опытом в комментариях.
Особенно интересны реальные кейсы, где удалось найти золотую середину между балансом и сохранением репрезентативности данных.
Автор:
Михаил Шардин
🔗 Моя онлайн-визитка
📢 Telegram «Умный Дом Инвестора»
17 октября 2025
рискнул бы не согласиться с тезисом о неважности алгоритмов
взять хотя бы вчерашний день
из-за произошедших событий придется заново обучать некоторые алгоритмы, хотя другие демонстрируют поразительную стойкость к такого рода явлениям, при этом все используют почти один и тот же входной набор данных
но, кажется мне, что даже новое переобучение не поможет… а вот почему не поможет, — это надо сильно подумать
Согласно Гомеру Сизиф был очень умный и хитрый человек. У него одна крупная проблема была. У него блога не было. И телеграм канала.
Если нет, то самому можно сделать.
1) Предварительная сортировка по возрастанию.
2) Отсчитываете 1/3 и 2/3 от начала. Получаете номера (и затем соответствующие им значения) границ трёх массивов.
У меня текстовый датасет из ~104K сообщений, размеченный по трём классам (негативный/-1, нейтральный/0, позитивный/+1) для разных временных окон. Проблема в сильном дисбалансе:
Текущее распределение классов:
* 5 min: -1 (9.7%), 0 (81.1%), 1 (9.2%)
* 15 min: -1 (9.1%), 0 (82.0%), 1 (8.9%)
* 60 min: -1 (8.1%), 0 (84.0%), 1 (7.9%)
Моя идея: удалить из класса 0 «истинно нейтральные» примеры — те, у которых целевая метрика близка к нулю и z-score низкий (нет статистической значимости).
Данные по классу 0 (для 5 мин):
* 61.7% имеют |z-score| < 0.5 (очень низкая значимость)
* 87.8% имеют |z-score| < 1.0 (слабая значимость)
* 99.9% имеют малое абсолютное значение целевой метрики
Мои вопросы:
* Насколько корректен такой подход для балансировки? Не теряю ли я важную информацию о «настоящих нейтральных» примерах?
* Какой порог по z-score посоветуешь использовать? Склоняюсь к |z| < 1.0 (это даст удаление ~74K из 84K нейтральных, останется ~30K примеров с более-менее равными классами).
* Может, есть лучшие стратегии для такой задачи, кроме андерсэмплинга нейтрального класса?
3. Есть несколько стратегий: undersampling, oversampling и взвешивание классов. Можно отдельно почитать про каждый, инфы много
2. Тут не посоветую, подбирается по данным.
1. Ты используешь undersampling. Вполне корректно. Можно для начала просто рандомно взять необходимое количество сэмплов из общей выборки и провести 5-10 экспериментов, посмотреть как будут меняться метрики классификации в зависимости от взятых рандомно сэмплов. Если сильно меняются — нужно понять почему так происходит. Возможно у тебя внутри класса 0 будут подклассы. Если не меняются — значит просто бери рандомные, они из одного пространства признаков.
Александр Чекмарев, аккаунт два дня назад зарегистрирован, фотка сгенерирована, упоминаете решение которое не работает.
Реклама?
Прочитал дописанное. Все методы известные основаны на какой-то идее и здравом смысле, поэтому сразу можно переходить к собственным идеям, пусть и повторяющим известные, и искать приемлемый результат. По ходу собственные оценки идеи и подхода могут разворачиваться на противоположные.
Первая попытка – веса сообщениям. Нулевые должны стать в 10 раз легче, чем крайние. И с изменёнными на веса сообщениями работать как до того.
Вторая попытка – прикрутить какую-либо числовую характеристику сообщениям и попытаться найти такие её значения, что присущи только нулевым сообщениям. Тогда часть из них удастся отфильтровывать на входе. Например, логарифм длины сообщения. Разбить на классы по этому параметру с шагом 0,1. Составить таблицу со столбцами: класс логарифма длины, класс сообщения, z-score, абсолютное значение целевой метрики.
Вдруг окажется, что можно сгруппировать по первому столбцу с некоторыми функциями от других столбцов (среднее, минимум и т.п.), что часть классов первого столбца можно будет не рассматривать, а в оставшихся будет удобная и подходящая информация.