en
Feedback
Data Science Private Sharing

Data Science Private Sharing

Open in Telegram

Советы и лайфхаки для соревновательного (в основном) дата сайнса, о которых не расскажут на курсах. Если есть идеи, которыми хотите поделиться, пишите -> @slivka_83 Tags: #EDA #Evaluation #Models #TimeSeries #Train #Preprocessing #Valid

Show more
1 340
Subscribers
-124 hours
+57 days
+2630 days
Posts Archive
#курс После долгих лет (альфа-)тестирования, курс "Алгоритмы Машинного обучения с нуля" наконец-то выходит в свет (бета-тестирование :) Курс бесплатный :) На Степике: https://stepik.org/course/68260 Курс посвящен реализации всех классических алгоритмов машинного обучения с нуля. На чистом питоне + нампай и пандас. Упор в курсе будет делаться именно на алгоритмы. Хотя и немного математики тоже присутствует. Пока реализовано 6 уроков: - Два вида линейных моделей - Деревья решений (классификация и регрессия) - Случайный лес (классификация и регрессия) Остальные будут открываться по мере готовности. З.Ы. Для успешного прохождения курса вам понадобятся знания основ МЛ, а также уверенное владение питоном.

За инфошумом вокруг всяких ChatGPT и прочих Diffusion-моделей вы могли не заметить появления новой SOTA среди табличных данных - Dummy-алгоритмов. Одно из главных их преимуществ - для них практически не нужно готовить фичи (почти как в нейронках). В скалерн завезли две их реализации: для классификации и для регрессии. - https://scikit-learn.org/stable/modules/generated/sklearn.dummy.DummyClassifier.html - https://scikit-learn.org/stable/modules/generated/sklearn.dummy.DummyRegressor.html Использовать довольно просто:
from sklearn.dummy import DummyRegressor
model = DummyRegressor()
model.fit(X, y)
Думаю скоро они займут топовые строчки в соревнованиях. Уже удалось применить их в деле?

Всем привет :) Почти 2 месяца ничего не постил. А это потому, что был очень занят - писал лучший курс по машинному обучению (и другие курсы ему завидуют :) А если серьезно, то аналогов такому курсу и в правду не встречал. Курс посвящен реализации всех классических алгоритмов машинного обучения с нуля. На чистом питоне + нампай и пандас. Упор в курсе будет делаться именно на алгоритмы. Хотя и немного математики там есть. Курс бесплатный :) Пока реализовал 6 модулей: два вида линейных моделей, деревьев решений и случайного леса. Остальные будут добавляться по мере готовности. Сейчас ищу 3-4 человека, которые помогут протестировать задания перед публикацией в открытый доступ. От кандидатов жду понимания основ МЛ, умения писать на питоне и знания нампай и пандас. Плюс свободное время. Кто хочет - пишите в личку.

#Tip32 #Train Самый простой способ борьбы с выбросами (о котором не расскажут на курсах :) 1. Обучаете модель. 2. Делаете пре
#Tip32 #Train Самый простой способ борьбы с выбросами (о котором не расскажут на курсах :) 1. Обучаете модель. 2. Делаете предсказание на трейне. 3. Объекты, у которых самые большие ошибки выкидываете из трейна. З.Ы. Для задачи регрессии возможно стоит попробовать метрику MAE, поскольку MSE сильнее штрафует за большие ошибки (а значит лучше борется с выбросами).

#Tip31 #Train Обычно оптуну воспринимают как инструмент оптимизации гипер-параметров модели. Но ее возможности несколько шире. Например, можно повесить на нее и препроцессинг :) Вот небольшой пример. Допустим у вас есть датасет. В датасете есть колонки с пропусками. Колонки, в которых очень много пропусков - бесполезны и по-хорошему от них нужно избавиться. Но какой процент считать бесполезным? Выкидывать колонки, в которых более 90% пропусков? Более 80%? 70%? Можно пробовать выяснять это вручную, а можно поручить это опутне. Примерно так:
nulls_perc = (X.isna().sum() / X.shape[0] * 100).astype(int).sort_values(ascending=False)

def objective(trial):
    params = {
        'objective': 'regression',
        'metric': 'mse',
        'learning_rate': trial.suggest_float('learning_rate', 1e-5, 0.7, log=True),
        'num_leaves': trial.suggest_int('num_leaves', 20, 150),
        'verbose': -1
    }
    
    nulls_max = trial.suggest_int('nulls_max', 10, 100)
    f_cols = list(nulls_perc[nulls_perc < nulls_max].index)

    X_train = train[f_cols]
    X_test = test[f_cols]

    model = lgbm.train(
        params = params,
        train_set = lgbm.Dataset(X_train, y_train),
        valid_sets = lgbm.Dataset(X_test, y_test),
        verbose_eval = None
    )

    score = model.best_score['valid_0']['l2']
    print(score, len(f_cols))

    return score

study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=3000, timeout=300)
Здесь мы в начале подсчитываем процент пропусков в каждой колонке. Затем внутри цикла генерируем кол-во пропусков которое хотим оставить. Отбираем колонки по этому показателю и формируем датасеты для обучения и валидации. Точно также можно выкидывать статичные колонки, можно перебирать способы заполнение пропусков и кучу других препроцессинговых задач.

Написал небольшой эпос о библиотеке transformers. И хотя текста много это все равно только лишь введение. Функционала в библи
Написал небольшой эпос о библиотеке transformers. И хотя текста много это все равно только лишь введение. Функционала в библиотеке слишком много. https://habr.com/ru/post/704592/ Для тех кто не в курсе: библиотека Transformers предоставляет доступ к куче современных предобученных DL-моделей. И на текущий момент является чуть ли не аналогом скалерна в мире Deep Learning.

#Tip30 #Train В отличии от других бустингов в LGBM деревья растут асимметрично (по листьям). В то время как в CatBoost и XGBo
#Tip30 #Train В отличии от других бустингов в LGBM деревья растут асимметрично (по листьям). В то время как в CatBoost и XGBoost рост происходит по уровням. И это декларируется разработчиками LGBM как одно из основных преимуществ. И тут закралась ловушка: если вы ограничите глубину дерева в LGBM (а для бустингов рекомендуются не глубокие деревья), то вы по сути превратите его в симметричное урезанное дерево! Именно поэтому по умолчанию в LGBM глубина деревьев (max_depth) = -1 (что значит - бесконечная), а в CatBoost и XGBoost глубина = 6. Но бесконечно расти тоже не вариант - так мы просто запомним все данные. Поэтому, чтобы ограничить глубину деревьев используйте такие параметры как: num_leaves — максимальное количество листьев в одном дереве min_data_in_leaf — минимальное количество данных в одном листе min_data_in_bin — минимальное количество данных внутри одного бина min_data_per_group — минимальное количество данных на одно значение категориальной фичи min_gain_to_split — минимальный прирост, которое дает разделение min_sum_hessian_in_leaf — минимальная сумма гессиана в одном листе Считается, что асимметричные деревья более склонны к переобучению, особенно на маленьких датасетах. В этом случае рекомендуется задействовать max_depth. Также стоит использовать max_depth на очень больших датасетах - иначе модель будет слишком долго учиться. З.Ы. Недавно поведение аналогичное LGBM и XGBoost реализовали в катбусте.

Залил на Хабр статью про библиотеку Voilà (читается "вуаля"), которая позволяет конвертировать ноутбуки в веб-приложения. htt
Залил на Хабр статью про библиотеку Voilà (читается "вуаля"), которая позволяет конвертировать ноутбуки в веб-приложения. https://habr.com/ru/post/698662/

#Tip29 #Train Случайный лес не переобучается! Но с оговоркой... :) Лес переобучается, но он не переобучается от увеличения ко
#Tip29 #Train Случайный лес не переобучается! Но с оговоркой... :) Лес переобучается, но он не переобучается от увеличения кол-ва деревьев (при прочих разумных условиях). Есть у Случайного леса такое свойство, что по мере увеличения кол-ва деревьев кривые обучения выходят на плато и дальше на их предсказание влияет только шум. Для бустинга же бездумное увеличение кол-ва деревьев это прямой путь к оверфиту. Но если вы зададите для леса глубину скажем 1000, то он конечно же переобучится: просто запомнит данные, вместо того чтобы выучить закономерности. Интуитивно это можно понять так... Представим себе генеральную совокупность на 10 000 000 экземпляров. Возьмем из нее два случайных экземпляра и посчитаем их среднее. Очевидно, что это среднее будет сильно отличаться от среднего генеральной совокупности. Также и для трех, четыре, пяти... экземпляров. Но если мы возьмем 1 000 000 случайных экземпляров, то среднее будет очень близко к генеральной совокупности. И добавление миллион первого, второго, третьего экземпляра сильно на среднее не повлияет. Лес точно также усредняет предсказания своих деревьев. И в определенный момент кол-во деревьев становится достаточным, и добавление новых уже ни на что не виляет (если не считать шум).

Написал статью про фреймворк Hydra https://habr.com/ru/post/696820/ Гидра предназначена для управления файлами конфигурации в
Написал статью про фреймворк Hydra https://habr.com/ru/post/696820/ Гидра предназначена для управления файлами конфигурации в ML-проектах.

#Tip28 #Train Nested Cross-Validation - самая дорогая из "классических" схем валидации. Состоит из двух вложенных кросс-валид
#Tip28 #Train Nested Cross-Validation - самая дорогая из "классических" схем валидации. Состоит из двух вложенных кросс-валидаций: внешней и внутренней. Внутренняя используется для подбора гипер-параметров/выбора модели, а внешняя - для оценки модели. При обучении модели вам нужно решить две задачи: подобрать гипер-параметры и оценить модель. Если использовать для них только одну кросс-валидацию, то это может привести к чрезмерно оптимистичной оценке модели. Поскольку одни и те же данные используются и для подбора гипер-параметров и для оценки модели. Обычно в этом случае для финальной оценки выделяют тестовую часть, которая никаким образом в обучении не участвует. Но тогда мы теряем часть данных для обучения. С помощью Nested Cross-Validation можно задействовать все данные для обучения и получить корректную оценку. Алгоритм такой: 1. Делим весь датасет на фолды 2. Для каждого фолда: - Делим часть для обучения на свои фолды - Подбираем гипер-параметры - Обучаем одну модель на всей тренировочной части на лучших гипер-параметрах - Оцениваем модель на тестовой части 3. Усредняем скоры по всем внешним фолдам На выходе, помимо скоров, у нас будут N обученных моделей. Для предсказания используются все три, результаты усредняются. Т.к. такая схема очень дорогая по времени, то применять ее следует в двух случаях: 1. У вас очень маленький датасет. 2. У вас есть своя майнинг-ферма :) З.Ы. Для временного CV все аналогично просто оба цикла будут со сдвигом.

#Tip27 #Train При K-fold валидации прогнозы делаются на тестовых частях, которые не участвуют в обучении и эти прогнозы назыв
#Tip27 #Train При K-fold валидации прогнозы делаются на тестовых частях, которые не участвуют в обучении и эти прогнозы называются Out-of-Fold (OOF) Predictions. Обычно они используются по прямому назначению - оценки модели. Но можно их задействовать и более интересным способом - для стэкинга. Стэкинг это способ построения ансамбля моделей, в котором есть базовые модели и есть мета модель. Базовые модели обучаются на исходных данных, а мета-модель на предсказаниях базовых моделей. Обычно для построения стекинга исходный датасет делится на несколько крупных частей из-за чего все модели увидят меньше данных. Но благодаря Out-of-Fold Predictions можно реализовать обучение на всех (почти) данных. В соревновательном DS алгоритм в целом такой: - Разбиваем датасет с метками на трейн и эвал + у нас уже есть тестовый датасет от организаторов. - Трейн разбиваем на фолды. - Для каждого фолда: - Обучаем модель на тренировочной части. - Выполняем предсказание для тестовой части фолда и сохраняем предсказание в отдельный вектор, каждый элемент которого соответствует строке тренировочного датасета. - Выполняем предсказание для валидационного датасета. - Выполняем предсказание для тестового датасета. - Собранные предсказания на фолдах передаем в мета-модель как фичу. - Усредняем предсказания полученные для валидационного и тестового датасета. - С помощью мета-модели делаем предсказание для усредненных значений валидационного и тестового датасета. - Значения полученные для валидационного датасета используем для оценки, а значения полученные для тестового датасета заворачиваем в сабмит. Реализуется данный алгоритм обычно вручную. Варианты для изменений: - На фолдах можно обучить несколько видов базовых моделей, тогда на вход мета-модели пойдет несколько фичей. - На шаге обучения мета-модели можно присоединить фичи-предсказания к исходным фичам. Для большей эффективности ансамбля для базовых и мета-модели стараются задействовать разные алгоритмы (линейные/KNN/деревья).

Ловите еще одну статью :) На этот раз повещенную Evidently - библиотеке для мониторинга качества данных и моделей в проде. ht
Ловите еще одну статью :) На этот раз повещенную Evidently - библиотеке для мониторинга качества данных и моделей в проде. https://habr.com/ru/post/692272/ Лайки приветствуются :)

Написал на Хабре еще один туториал (в рамках курса ML System Design). На этот раз посвященный ClearML - системе трекинга Ml-э
Написал на Хабре еще один туториал (в рамках курса ML System Design). На этот раз посвященный ClearML - системе трекинга Ml-экспериментов. https://habr.com/ru/post/691314/ Заходим, читаем и не забываем ставить лайки :)

Написал на Хабре туториал про Dagster - оркестратор предназначенный для организации конвейеров обработки данных: ETL, проведе
Написал на Хабре туториал про Dagster - оркестратор предназначенный для организации конвейеров обработки данных: ETL, проведение тестов, формирование отчетов, обучение ML-моделей. https://habr.com/ru/post/690342/ Заходим, не стесняемся, лайкаем :) З.Ы. Туториал написан в рамках прохождения курса ML System Design (можете еще присоединиться): https://ods.ai/tracks/ml-system-design-22

#Tip26.1 #EDA Для понимания как строится PDP попробуем построить его в ручную. Алгоритм такой: - Выбираем какую-нибудь фичу -
#Tip26.1 #EDA Для понимания как строится PDP попробуем построить его в ручную. Алгоритм такой: - Выбираем какую-нибудь фичу - Вычисляем все ее уникальные значения (для непрерывной фичи можно взять сколько-то квантильных значений) - Проходимся по каждому из них и: - В исходном датасете для нашей фичи заменяем все значения на одно - текущее - Делаем предсказание - Усредняем полученные предсказания И так для каждого уникального значения. В итоге получаем набор пар: (уникальное значение - средний предикт) По смыслу мы как бы спрашиваем модель: а что если бы фича принимала бы только одно значение из возможного диапазона (при этом другие фичи не трогаем) - какими тогда стали бы предсказания? - Выводим их на графике. З.Ы. Также для демонстрации влияния на отдельные примеры выведем случайные 50 записей.
# Считаем PDP
col = 'grade'
uniq_values = sorted(X[col].unique())
preds = {}
for v in uniq_values:
  X_copy = X.copy()
  X_copy[col] = v
  preds[v] = model.predict(X_copy)
preds = pd.DataFrame(preds)
pdp = preds.mean()

# Выбираем лучайные 50 записей
samp = preds.sample(50).copy()
samp = samp.reset_index().melt('index', var_name='cols', value_name='vals')

# Строим графики
plt.figure(figsize=(13,6))
sns.lineplot(data=samp, x='cols', y='vals', hue='index', legend=False, palette='GnBu', alpha=0.2)
sns.lineplot(x=pdp.index, y=pdp, color='red', linewidth=2)
plt.xlabel(col)
plt.ylabel('PDP');

#Tip26 #EDA Partial dependence plots (PDP) — это график, который позволяет понять, как различные значения конкретной фичи вли
#Tip26 #EDA Partial dependence plots (PDP) — это график, который позволяет понять, как различные значения конкретной фичи влияют на предсказания модели. Под капотом PDP меняет исходные значения целевой фичи и смотрит как изменяются предсказания модели. По сути PDP показывает ожидаемое среднее значение таргета при различных значения интересующей нас фичи. Строятся PDP в двух вариантах - для одной фичи и для пары фичей. Обычно для графика выбирают наиболее значимые для модели фичи. Т.к. PDP работает с уже обученной моделью, то это еще один способ приоткрыть завесу черного ящика (наряду с SHAP и пр.). PDP можно построить либо с помощью скалерна (но на вход принимаются только родные для скалерна модели):
fig, ax = plt.subplots(figsize=(18.5,4.5))
features = ['bahrooms','sqf_living','yr_buil']
PartialDependenceDisplay.from_estimator(clf, X, features, ax=ax);
Либо с помощью сторонних пакетов, например PDPbox (https://github.com/SauceCat/PDPbox):
features_to_plot = ['sqf_living','bahrooms']
inter1 = pdp.pdp_interact(model=model, dataset=X, model_features=fcols, features=features_to_plot)
pdp.pdp_interact_plot(pdp_interact_out=inter1, feature_names=features_to_plot, plot_type='contour')
plt.show()
З.Ы. У PDPbox есть еще много других интересных графиков.

#Tip25 #TimeSeries #Valid TimeSeriesSplit - известный способ разбиения временных данных для кросс-валидации из скалерна. Мето
#Tip25 #TimeSeries #Valid TimeSeriesSplit - известный способ разбиения временных данных для кросс-валидации из скалерна. Метод разбиения, который в нем реализован называется Expanding window. Но наука о временных рядах знает гораздо больше способов разбить временные данные. Основных два: - Expanding Window - Sliding Window А дальше включается воображение: - Нахлесты между периодами - Пробел между трейном/валидом/тестом - Способ выделения тестовой выборки Как уже было сказано, Expanding Window можно найти в скалерне. Для Sliding Window и других ухищрений нужно либо писать свой код (основные ML-библиотеки принимают готовые сплиты в виде индексов строк), либо поискать на гитхабе: https://github.com/WenjieZ/TSCV https://github.com/AaronOS0/Time-series-Cross-validation https://github.com/marmurar/jano и прочие...

#Tip24 #Train Для честной проверки все методы валидации включают в себя тестовую выборку. Тест при этом никак не используется
#Tip24 #Train Для честной проверки все методы валидации включают в себя тестовую выборку. Тест при этом никак не используется для обучения. Но в нем может содержаться полезная информация. В самом простом случаи можете просто объединить трейн и тест и обучить модель заново с лучшими гипер-праметрами. Но они были подобраны для другого датасета, и могут быть не оптимальными для нового. Поэтому для градиентного бустинга придумали такой фокус: 1. Разбиваете датасет на трейн и тест. 2. Обучаете модель и подбираете наилучшие гипер-параметры. Проверяете модель на тесте. 3. Объединяете трейн и тест. 4. Заново обучаете модель на полном датасете с найденными гиперпарамтрами, но только увеличиваете в них количество итераций на % теста. Т.е. если у вас получилось 100 итераций, а тест вы взяли в 20%, то для нового обучения выставляете кол-во итераций в 120. 5. Делаете предсказание с новой моделью. При этом протестировать ее сможете только на лидерборде. Данный фокус не имеет под собой научного обоснования, но иногда докидывает...

#Tip23 #Preprocessing pipe - это метод реализации паплайна в датафреймах пандас посредством последовательной цепочки преобраз
#Tip23 #Preprocessing pipe - это метод реализации паплайна в датафреймах пандас посредством последовательной цепочки преобразований. З.Ы. Не путать с Pipeline из скалерна - это разные вещи. Предположим, у нас есть ряд функций, каждая из которых отвечает за отдельный вид преобразований. Тогда в пандасе пайплайн можно реализовать так: def normilize(df): ... return df def fill_null(df, method): ... return df def parse_time(df): ... return df new_df = (df .pipe(normilize) .pipe(fill_null, method='median') .pipe(parse_time) )