Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Примерно в декабре прошлого года Scikit-Learn выпустила крупное стабильное обновление (версия 1.2.0–1), и, наконец, я могу попробовать некоторые из новых функций. Теперь Scikit-Learn более совместим с Pandas, некоторые новые функции могут помочь нам с регрессией, а также с задачами классификации. Ниже я рассматриваю некоторые из новых обновлений с примерами того, как их использовать. Давайте начнём!

Совместимость с Pandas

Применение некоторой стандартизации данных перед их использованием для обучения модели ML, такой как регрессия или нейронная сеть, является распространённым методом, позволяющим убедиться, что различные функции с различными диапазонами приобретают одинаковую важность (если или когда это необходимо) для прогнозов. Scikit-Learn предоставляет различные API предварительной обработки, такие как StandardScaler, MaxAbsScaler и т.д. В более новой версии можно сохранить формат фрейма данных даже после предварительной обработки, как показано ниже:

from sklearn.datasets import load_wine from sklearn.model_selection import train_test_split ######################## X, y = load_wine(as_frame=True, return_X_y=True) # available from version >=0.23; as_frame ######################## X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0) X_train.head(3)
Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Новая версия включает в себя возможность сохранить этот формат фрейма данных даже после стандартизации:

############ # v1.2.0 ############ from sklearn.preprocessing import StandardScaler scaler = StandardScaler().set_output(transform="pandas") ## change here scaler.fit(X_train) X_test_scaled = scaler.transform(X_test) X_test_scaled.head(3)
Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Раньше это изменило бы формат на массив Numpy:

########### # v 0.24 ########### scaler.fit(X_train) X_test_scaled = scaler.transform(X_test) print (type(X_test_scaled)) >>> <class 'numpy.ndarray'>

Поскольку формат фрейма данных остаётся неизменным, нам не нужно следить за столбцами, как нам нужно было делать это раньше. Анализ и построение графиков становятся проще:

fig = plt.figure(figsize=(8, 5)) fig.add_subplot(121) plt.scatter(X_test['proline'], X_test['hue'], c=X_test['alcohol'], alpha=0.8, cmap='bwr') clb = plt.colorbar() plt.xlabel('Proline', fontsize=11) plt.ylabel('Hue', fontsize=11) fig.add_subplot(122) plt.scatter(X_test_scaled['proline'], X_test_scaled['hue'], c=X_test_scaled['alcohol'], alpha=0.8, cmap='bwr') # pretty easy now in the newer version to see the effect plt.xlabel('Proline (Standardized)', fontsize=11) plt.ylabel('Hue (Standardized)', fontsize=11) clb = plt.colorbar() clb.ax.set_title('Alcohol', fontsize=8) plt.tight_layout() plt.show()
Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Даже когда мы создаём конвейер, каждый трансформатор в конвейере может быть сконфигурирован для возврата фреймов данных, как показано ниже:

from sklearn.pipeline import make_pipeline from sklearn.svm import SVC clf = make_pipeline(StandardScaler(), SVC()) clf.set_output(transform="pandas") # change here svm_fit = clf.fit(X_train, y_train) print (clf[:-1]) # StandardScaler print ('check that set_output format indeed remains even after we build a pipleline: ', '\n') X_test_transformed = clf[:-1].transform(X_test) X_test_transformed.head(3)
Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Извлечение набора данных происходит быстрее и эффективнее

OpenML- это открытая платформа для обмена наборами данных, а Dataset API в Sklearn предлагает функцию fetch_openml для их извлечения. С обновлённым Sklearn этот процесс стал более эффективен с точки зрения использования памяти и времени.

from sklearn.datasets import fetch_openml start_t = time.time() X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True, parser="pandas") # # parser pandas is the addition in the version 1.2.0 X = X.select_dtypes(["number", "category"]).drop(columns=["body"]) print ('check types: ', type(X), '\n', X.head(3)) print ('check shapes: ', X.shape) end_t = time.time() print ('time taken: ', end_t-start_t)

Использование parser='pandas' значительно сокращает время выполнения и потребление памяти. Можно легко проверить потребление памяти, используя библиотеку psutil, как показано ниже:

print(psutil.cpu_percent())

Графики частичной зависимости: Категориальные характеристики

Графики частичной зависимости существовали и раньше, но только для числовых объектов. Теперь они были расширены и для категориальных объектов.

Как написано в документации Sklearn:

Графики частичной зависимости показывают зависимость между целевыми показателями и набором входных признаков, представляющих интерес, с незначительным превышением значений всех других входных признаков. Интуитивно мы можем интерпретировать частичную зависимость как ожидаемый целевой отклик в зависимости от интересующих входных характеристик.

Используя приведённый выше набор данных "titanic", мы можем легко построить график частичной зависимости категориальных признаков:

import numpy as np import matplotlib.pyplot as plt import pandas as pd from sklearn.datasets import fetch_openml start_t = time.time() X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True, parser="pandas") # parser pandas is the addition in the version 1.2.0 X = X.select_dtypes(["number", "category"]).drop(columns=["body"]) print ('check types: ', type(X), '\n', X.head(3)) print ('check shapes: ', X.shape) ### drop nans print ('check for nans in cols: ', X.isna().sum()) X_nonan = X.dropna(how='any', inplace=False) print ('check new shapes: ', X_nonan.shape) nonan_indices = X_nonan.index.to_list() y_nonan = y[y.index.isin(nonan_indices)] print ('check shape y: ', y_nonan.shape) # print ('check for indices: ', X_nonan.index.to_list()) from sklearn.preprocessing import OrdinalEncoder from sklearn.pipeline import make_pipeline from sklearn.ensemble import GradientBoostingRegressor #HistGradientBoostingRegressor from sklearn.compose import ColumnTransformer #### build a pipeline categorical_features = ["pclass", "sex", "embarked"] model = make_pipeline(ColumnTransformer(transformers=[("cat", OrdinalEncoder(), categorical_features)], remainder="passthrough",), GradientBoostingRegressor(random_state=0),).fit(X_nonan, y_nonan) # gradientboosting regressor doesn't work with nan entries from sklearn.inspection import PartialDependenceDisplay fig, ax = plt.subplots(figsize=(14, 4), constrained_layout=True) disp = PartialDependenceDisplay.from_estimator(model, X_nonan, features=["age", "sex", ("pclass", "sex")], categorical_features=categorical_features, ax=ax,) fig.savefig(path_to_file + './part_disp.png', dpi=200) ################ # with v 0.24 ################ # GBR_disp = plot_partial_dependence(model, X_NotNan, # ['age', 'sex', ('age', 'sex')], ax=ax) # >>> ValueError: could not convert string to float: 'female'

С помощью приведённого выше блока кода мы можем получить графики частичной зависимости, как показано ниже:

Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

С версией 0.24 мы бы получали ошибку значения для категориальных переменных:

>>> ValueError: could not convert string to float: ‘female’

Построение графика остатков (регрессионные модели)

Для анализа производительности классификационной модели в Sklearn metrics API в старых версиях (0.24) существовали процедуры построения графиков, такие как PrecisionRecallDisplay , RocCurveDisplay. В новом обновлении можно сделать аналогичное для регрессионных моделей. Давайте посмотрим на пример ниже:

from sklearn.linear_model import Lasso from sklearn.datasets import load_diabetes from sklearn.model_selection import cross_val_predict from sklearn.metrics import PredictionErrorDisplay X_db, y_db = load_diabetes(return_X_y=True, as_frame=True) print (X_db.head(3)) lasso001 = Lasso(alpha=0.01, max_iter=int(10e5)) y_pred = cross_val_predict(lasso001, X_db, y_db, cv=5) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6)) PredictionErrorDisplay.from_predictions(y_db, y_pred=y_pred, kind="actual_vs_predicted", subsample=100, ax = ax1, random_state=0,) ax1.set_title("Actual vs. Predicted values", fontsize=11) PredictionErrorDisplay.from_predictions(y_db, y_pred=y_pred, kind="residual_vs_predicted", subsample=100, ax = ax2, random_state=0,) ax2.set_title("Residuals vs. Predicted Values", fontsize=11) fig.suptitle("Prediction Results after Cross-Validation (Regression & Residual)", fontsize=14) plt.tight_layout() plt.show()
Новая версия Scikit-Learn (1.2.0–1) больше подходит для анализа данных

Хотя всегда можно построить подогнанную линию и остатки с помощью matplotlib или seaborn, после того, как мы определились с наилучшей моделью, здорово иметь возможность быстро проверять результаты непосредственно в среде Sklearn.

В новом Sklearn доступно ещё несколько улучшений / дополнений, но я обнаружил, что эти 4 основных улучшения чаще всего оказываются особенно полезными для стандартного анализа данных.

Ссылки на литературу

[2] Основные моменты выпуска Sklearn: Video

[3] Все графики и коды: My GitHub

Статья была взята из следующего источника:

22
3 комментария

Спасибо за обратную связь!

1
Ответить

Здравствуйте. Порекомендуйте пожалуйста актуальные MustRead книги на русском языке по ML и BigData

Ответить

Добрый день! https://t.me/datascienceiot/2280

1
Ответить