{"id":14291,"url":"\/distributions\/14291\/click?bit=1&hash=257d5375fbb462be671b713a7a4184bd5d4f9c6ce46e0d204104db0e88eadadd","hash":"257d5375fbb462be671b713a7a4184bd5d4f9c6ce46e0d204104db0e88eadadd","title":"\u0420\u0435\u043a\u043b\u0430\u043c\u0430 \u043d\u0430 Ozon \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u0442\u0430\u043c \u043d\u0435 \u043f\u0440\u043e\u0434\u0430\u0451\u0442","buttonText":"","imageUuid":""}

19 самых элегантных трюков Sklearn, которые я нашёл после 3 лет использования

Узнайте о 19 функциях Sklearn, которые вы никогда не видели, являющиеся прямой и элегантной заменой обычных операций, которые вы выполняете вручную.

Введение

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

Итак, я решил составить список самых элегантных и важных из них и кратко объяснить их, чтобы вы могли значительно расширить свой набор инструментов Sklearn. Наслаждайтесь!

1. covariance.EllipticEnvelope

Распределения часто имеют выбросы. Многие алгоритмы имеют дело с выбросами, и EllipticalEnvelope - это пример, который напрямую встроен в Sklearn. Преимущество этого алгоритма в том, что он исключительно хорошо обнаруживает выбросы в нормально распределенных (гауссовских) функциях:

import numpy as np from sklearn.covariance import EllipticEnvelope # Create a sample normal distribution X = np.random.normal(loc=5, scale=2, size=50).reshape(-1, 1) # Fit the estimator ee = EllipticEnvelope(random_state=0) _ = ee.fit(X) # Test test = np.array([6, 8, 20, 4, 5, 6, 10, 13]).reshape(-1, 1) # predict returns 1 for an inlier and -1 for an outlier >>> ee.predict(test) array([ 1, 1, -1, 1, 1, 1, -1, -1])

Чтобы протестировать оценщик, мы создаем нормальное распределение со средним значением 5 и стандартным отклонением 2. После того, как оно обучено, мы передаем в его метод predict несколько случайных чисел. Метод возвращает -1 для выбросов в test 20, 10, 13.

2. feature_selection.RFECV

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

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

from sklearn.datasets import make_regression from sklearn.feature_selection import RFECV from sklearn.linear_model import Ridge # Build a synthetic dataset X, y = make_regression(n_samples=10000, n_features=15, n_informative=10) # Init/fit the selector rfecv = RFECV(estimator=Ridge(), cv=5) _ = rfecv.fit(X, y) # Transform the feature array >>> rfecv.transform(X).shape (10000, 10)

Поддельный набор данных имеет 15 признаков, 10 из которых информативны, а остальные избыточны. Мы подгоняем 5-кратный RFECV с регрессией Ridge в качестве оценки. После обучения вы можете использовать метод transform, чтобы отбросить избыточные функции. Вызов .shape показывает нам, что оценщику удалось отбросить все 5 ненужных функций.

3. ensemble.ExtraTrees

Несмотря на то, что случайные леса мощные и могущественные, риск переобучения очень высок. Поэтому Sklearn предлагает альтернативу RF, называемую ExtraTrees (как классификатор, так и регрессор).

Слово «extra» означает не больше деревьев, а больше случайности. Алгоритм использует другой тип дерева, который очень похож на деревья решений.

Единственное отличие состоит в том, что вместо вычисления порогов разделения при построении каждого дерева эти пороги рисуются случайным образом для каждого признака, и в качестве правила разделения выбирается наилучший порог. Это уменьшает дисперсию за счет небольшого увеличения смещения:

from sklearn.ensemble import ExtraTreesRegressor, RandomForestRegressor from sklearn.model_selection import cross_val_score from sklearn.tree import DecisionTreeRegressor X, y = make_regression(n_samples=10000, n_features=20) # Decision trees clf = DecisionTreeRegressor(max_depth=None, min_samples_split=2, random_state=0) scores = cross_val_score(clf, X, y, cv=5) >>> scores.mean() 0.6376080094392635 # Random Forest clf = RandomForestRegressor( n_estimators=10, max_depth=None, min_samples_split=2, random_state=0 ) scores = cross_val_score(clf, X, y, cv=5) >>> scores.mean() 0.8446103607404536 # ExtraTrees clf = ExtraTreesRegressor( n_estimators=10, max_depth=None, min_samples_split=2, random_state=0 ) scores = cross_val_score(clf, X, y, cv=5) >>> scores.mean() 0.8737373931608834

Как видите, ExtraTreesRegressor работает лучше, чем Random Forests, на синтетическом наборе данных.

Подробнее о Extremely Randomized Trees читайте в официальном руководстве пользователя .

4. impute.IterativeImputer и KNNImputer

Если вы ищете более надежные и продвинутые методы вменения, чем SimpleImputer, Sklearn снова поможет вам.

Подпакет sklearn.impute включает в себя два алгоритма вменения на основе моделей — KNNImputer и IterativeImputer.

Как следует из названия, KNNImputer использует алгоритм k-ближайших соседей, чтобы найти лучшую замену отсутствующим значениям:

from sklearn.impute import KNNImputer # Code taken from Sklearn user guide X = [[1, 2, np.nan], [3, 4, 3], [np.nan, 6, 5], [8, 8, 7]] imputer = KNNImputer(n_neighbors=2) >>> imputer.fit_transform(X) array([[1. , 2. , 4. ], [3. , 4. , 3. ], [5.5, 6. , 5. ], [8. , 8. , 7. ]])

Более надёжным алгоритмом является IterativeImputer. Он находит пропущенные значения, моделируя каждую функцию с пропущенными значениями как функцию остальных функций. Этот процесс выполняется пошагово в циклическом режиме. На каждом шаге один признак с отсутствующими значениями выбирается в качестве цели (y), а остальные выбираются в качестве массива признаков (X). Затем используется регрессор для прогнозирования отсутствующих значений y, и этот процесс продолжается для каждого признака до времени max_iter (параметр IterativeImputer).

В результате для одного пропущенного значения генерируются несколько прогнозов. Преимущество этого заключается в том, что каждое отсутствующее значение рассматривается как случайная величина и связывается с присущей им неопределенностью:

from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer from sklearn.linear_model import BayesianRidge imp_mean = IterativeImputer(estimator=BayesianRidge()) imp_mean.fit([[7, 2, 3], [4, np.nan, 6], [10, 5, 9]]) X = [[np.nan, 2, 3], [4, np.nan, 6], [10, np.nan, 9]] >>> imp_mean.transform(X) array([[ 6.95847623, 2. , 3. ], [ 4. , 2.6000004 , 6. ], [10. , 4.99999933, 9. ]])

Обнаружено, что BayesianRidge и ExtraTree работают лучше с IterativeImputer.

5. linear_model.HuberRegressor

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

Альтернативный алгоритм HuberRegressor. Вместо того, чтобы полностью удалять их, он придает выбросам меньший вес во время подгонки. Он имеет гиперпараметр epsilon, контролирующий количество выборок, которые следует классифицировать как выбросы. Чем меньше параметр, тем более устойчива модель к выбросам. Его API такой же, как и у любого другого линейного регрессора.

Ниже вы можете увидеть его сравнение с регрессором Байесовского хребта на наборе данных с сильными выбросами:

Как видите, HuberRegressor с epsilon 1.35 1.5, 1.75 удалось зафиксировать линию наилучшего соответствия, на которую не влияют выбросы.

Подробнее об алгоритме можно узнать из руководства пользователя .

6. tree.plot_tree

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

from sklearn.datasets import load_iris from sklearn.tree import DecisionTreeClassifier, plot_tree iris = load_iris() X, y = iris.data, iris.target clf = DecisionTreeClassifier() clf = clf.fit(X, y) plt.figure(figsize=(15, 10), dpi=200) plot_tree(clf, feature_names=iris.feature_names, class_names=iris.target_names);

Существуют и другие методы построения деревьев, например, в формате Graphviz. Узнайте о них из руководства пользователя .

7. linear_model.Perceptron

Самое крутое имя в этом списке принадлежит номеру 7 — Perceptron. Несмотря на причудливое название, это простой линейный двоичный классификатор. Отличительной особенностью алгоритма является то, что он подходит для крупномасштабного обучения и по умолчанию:

  • Не требует скорости обучения.
  • Не применяет регуляризацию.
  • Обновляет свою модель только при ошибках.

Это эквивалентно SGDClassifier loss='perceptron', eta=1, learning_rate="constant", penalty=None, но немного быстрее:

from sklearn.datasets import make_classification from sklearn.linear_model import Perceptron # Create a large dataset X, y = make_classification(n_samples=100000, n_features=20, n_classes=2) # Init/Fit/Score clf = Perceptron() _ = clf.fit(X, y) >>> clf.score(X, y) 0.91928

8. feature_selection.SelectFromModel

Другой оценщик выбора функций на основе модели в Sklearn — это SelectFromModel. Он не так надежен, как RFECV, но может быть хорошим вариантом для массивных наборов данных, поскольку требует меньших вычислительных затрат. Он также является оценщиком-оболочкой и работает с любой моделью, имеющей атрибуты .feature_importances_ или .coef_:

from sklearn.feature_selection import SelectFromModel # Make a dataset with 40 uninformative features X, y = make_regression(n_samples=int(1e4), n_features=50, n_informative=10) # Init the selector and transform feature array selector = SelectFromModel(estimator=ExtraTreesRegressor()).fit(X, y) >>> selector.transform(X).shape (10000, 8)

Как видите, алгоритму удалось отбросить все 40 избыточных функций.

9. metrics.ConfusionMatrixDisplay

Матрицы путаницы — святой Грааль задач классификации. На ней основано большинство метрик, таких как precision, recall, F1, ROC AUC и т.д. Sklearn позволяет вычислить и построить матрицу путаницы по умолчанию:

from sklearn.metrics import plot_confusion_matrix from sklearn.model_selection import train_test_split # Make a binary classification problem X, y = make_classification(n_samples=200, n_features=5, n_classes=2) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.5, random_state=1121218 ) clf = ExtraTreeClassifier().fit(X_train, y_train) fig, ax = plt.subplots(figsize=(5, 4), dpi=100) plot_confusion_matrix(clf, X_test, y_test, ax=ax);

Честно говоря, я бы не сказал, что мне нравится матрица путаницы по умолчанию. Их формат фиксирован — строки являются истинными метками, а столбцы — прогнозами. Кроме того, первая строка и столбец относятся к отрицательному классу, а вторая строка и столбец — к положительному. Некоторые люди могут предпочесть матрицу другого формата, возможно, транспонированную или перевернутую.

Например, мне нравится делать положительный класс первой строкой и первым столбцом, чтобы соответствовать формату, указанному в Википедии. Это помогает мне лучше выделить 4 термина матрицы — TP, FP, TN, FN. К счастью, вы можете построить пользовательскую матрицу с помощью другой функции ConfusionMatrixDisplay:

from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix clf = ExtraTreeClassifier().fit(X_train, y_train) y_preds = clf.predict(X_test) fig, ax = plt.subplots(figsize=(5, 4), dpi=100) cm = confusion_matrix(y_test, y_preds) cmp = ConfusionMatrixDisplay(cm, display_labels=["Positive", "Negative"]) cmp.plot(ax=ax);

Вы можете поместить матрицу путаницы cm в любой формат, который вы хотите, прежде чем передавать ее в ConfusionMatrixDisplay.

🔟. Generalized Linear Models

Нет смысла преобразовывать цель (y ), чтобы сделать ее нормально распределенной, если есть альтернативы, которые могут работать с другими типами распределений.

Например, Sklearn предлагает три обобщенные линейные модели для целевых переменных с распределением Пуассона, Твиди или Гаммы. Вместо того, чтобы ожидать нормального распределения, PoissonRegressor и TweedieRegressor может давать GammaRegressor надежные результаты для целей с соответствующими распределениями.

Кроме того, их API такие же, как и у любой другой модели Sklearn. Чтобы узнать, соответствует ли распределение цели трем вышеперечисленным, вы можете построить их PDF (функция плотности вероятности) на тех же осях с идеальным распределением.

Например, чтобы увидеть, соответствует ли цель распределению Пуассона, постройте ее PDF-распределение, используя Seaborn, kdeplot и постройте идеальное распределение Пуассона, выбрав его из Numpy, используя np.random.poisson той же оси.

11. ensemble.IsolationForest

Поскольку древовидные и ансамблевые модели обычно дают более надежные результаты, они также доказали свою эффективность при обнаружении выбросов. в Sklearn для обнаружения выбросов IsolationForest используется лес чрезвычайно случайных деревьев (tree.ExtraTreeRegressor ). Каждое дерево пытается изолировать каждую выборку, выбирая один признак и случайным образом выбирая значение разделения между максимальным и минимальным значениями выбранного признака.

Этот тип случайного разбиения создает заметно более короткие пути между корневым узлом и конечным узлом каждого дерева.

Таким образом, когда лес случайных деревьев в совокупности дает более короткие пути для определенных выборок, они, скорее всего, будут аномалиями — руководство пользователя Sklearn.

from sklearn.ensemble import IsolationForest X = np.array([-1.1, 0.3, 0.5, 100]).reshape(-1, 1) clf = IsolationForest(random_state=0).fit(X) >>> clf.predict([[0.1], [0], [90]]) array([ 1, 1, -1])

12. preprocessing.PowerTransformer

Многие линейные модели требуют некоторого преобразования числовых признаков, чтобы сделать их нормально распределенными. StandardScaler и MinMaxScaler работают довольно хорошо для большинства дистрибутивов.

Однако при наличии высокой асимметрии в данных затрагиваются основные показатели распределения, такие как среднее, медиана, минимальное и максимальное значения. Таким образом, простая нормализация и стандартизация не работают с асимметричными распределениями.

Вместо этого Sklearn PowerTransformer использует логарифмическое преобразование, чтобы максимально приблизить любую асимметричную функцию к нормальному распределению. Рассмотрим эти две функции в наборе данных Diamonds:

import seaborn as sns diamonds = sns.load_dataset("diamonds") diamonds[["price", "carat"]].hist(figsize=(10, 5));

Оба сильно перекошены. Давайте исправим это с помощью логарифмического преобразования:

from sklearn.preprocessing import PowerTransformer pt = PowerTransformer() diamonds.loc[:, ["price", "carat"]] = pt.fit_transform(diamonds[["price", "carat"]]) diamonds[["price", "carat"]].hist(figsize=(10, 5));

13. preprocessing.RobustScaler

Другой числовой преобразователь в Sklearn — это RobustScaler. Вероятно, вы можете догадаться, что он делает по его названию — он может преобразовывать функции таким образом, чтобы они были устойчивы к выбросам. Если в признаке присутствуют выбросы, их трудно сделать нормально распределенными, потому что они могут сильно искажать среднее значение и стандартное отклонение.

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

14. compose.make_column_transformer

В Sklearn есть сокращение для создания экземпляров Pipeline с функцией make_pipeline. Вместо того, чтобы называть каждый шаг и делать ваш код излишне длинным, функция просто принимает преобразователи и оценщики и выполняет свою работу:

from sklearn.impute import SimpleImputer from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler pipeline = make_pipeline(SimpleImputer(), StandardScaler(), ExtraTreesRegressor()) >>> pipeline Pipeline(steps=[('simpleimputer', SimpleImputer()), ('standardscaler', StandardScaler()), ('extratreesregressor', ExtraTreesRegressor())])

Для более сложных сценариев используется ColumnTransformer, у которого та же проблема — каждый шаг предварительной обработки должен быть назван, что делает ваш код длинным и нечитаемым. К счастью, Sklearn предлагает аналогичную функцию make_pipeline— make_column_transformer:

import seaborn as sns from sklearn.compose import make_column_transformer from sklearn.preprocessing import OneHotEncoder # Load diamonds dataset diamonds = sns.load_dataset("diamonds") X, y = diamonds.drop("price", axis=1), diamonds.price.values.reshape(-1, 1) # Isolate numeric and categorical cols num_cols = X.select_dtypes(include=np.number).columns cat_cols = X.select_dtypes(exclude=np.number).columns >>> make_column_transformer((StandardScaler(), num_cols), (OneHotEncoder(), cat_cols)) ColumnTransformer( transformers=[('standardscaler', StandardScaler(), Index(['carat', 'depth', 'table', 'x', 'y', 'z'], dtype='object')), ('onehotencoder', OneHotEncoder(), Index(['cut', 'color', 'clarity'], dtype='object'))] )

Как видите, использование make_column_transformer намного короче, и оно заботится об именовании каждого шага преобразования отдельно.

15. compose.make_column_selector

Если вы обратили внимание, мы использовали функцию select_dtypes вместе с атрибутом columns pandas DataFrames, чтобы изолировать числовые и категориальные столбцы. Хотя это работает, есть гораздо более гибкое и элегантное решение с использованием Sklearn.

Функция make_column_selector создает селектор столбца, который может быть передан непосредственно в экземпляры ColumnTransformer. Он имеет параметры dtype_include и dtype_exclude для выбора столбцов на основе типа данных.

Если вам нужен настраиваемый фильтр столбцов, вы даже можете передать регулярное выражение pattern, задав для других параметров значение None. Вот как это работает:

from sklearn.compose import make_column_selector make_column_transformer( (StandardScaler(), make_column_selector(dtype_include=np.number)), (OneHotEncoder(), make_column_selector(dtype_exclude=np.number)), )

Вместо того, чтобы передавать список имен столбцов, просто передайте экземпляр make_column_selector с соответствующими параметрами, и все готово!

16. preprocessing.OrdinalEncoder

Распространенной ошибкой среди новичков является использование LabelEncoder для кодирования порядковых категориальных признаков . Если вы заметили, LabelEncoder позволяет преобразовывать столбцы только по одному, а не одновременно, как OneHotEncoder. Вы можете подумать, что Sklearn ошибся!

На самом деле его следует использовать только для кодирования переменной ответа (y), как указано в документации . Чтобы закодировать массив функций (X), вы должны использовать OrdinalEncoder, который работает должным образом. Он преобразует порядковые категориальные столбцы в функцию с классами (0, n_categories - 1). И это делается для всех указанных столбцов в одной строке кода, что позволяет включать его в конвейеры.

from sklearn.preprocessing import OrdinalEncoder oe = OrdinalEncoder() X = [ ["class_1", "rank_1"], ["class_1", "rank_3"], ["class_3", "rank_3"], ["class_2", "rank_2"], ] >>> oe.fit_transform(X) array([[0., 0.], [0., 2.], [2., 2.], [1., 1.]])

17. metrics.get_scorer

В Sklearn встроено более 50 метрик, и их текстовые названия можно увидеть в файлах sklearn.metrics.SCORERS.keys(). В одном проекте вам, возможно, придется использовать несколько метрик и импортировать их, если вы используете их по отдельности.

Импорт множества метрик sklearn.metrics напрямую может загрязнить ваше пространство имен и стать излишне длинным. В качестве решения вы можете использовать функцию metrics.get_scorer для доступа к любой метрике с ее текстовым именем, даже не импортируя ее:

from sklearn.metrics import get_scorer >>> get_scorer("neg_mean_squared_error") make_scorer(mean_squared_error, greater_is_better=False) >>> get_scorer("recall_macro") make_scorer(recall_score, pos_label=None, average=macro) >>> get_scorer("neg_log_loss") make_scorer(log_loss, greater_is_better=False, needs_proba=True)

18. model_selection.HalvingGrid и HalvingRandomSearchCV

В версии 0.24 Sklearn мы познакомились с двумя экспериментальными оптимизаторами гиперпараметров: классами HalvingGridSearchCV и HalvingRandomSearchCV.

В отличие от своих исчерпывающих собратьев GridSearch и RandomizedSearch, новые классы используют технику, называемую последовательным делением пополам . Вместо обучения всех наборов-кандидатов (наборов комбинаций параметров) на всех данных параметрам задается только подмножество данных. Наихудшие кандидаты отфильтровываются путем их обучения на меньшем подмножестве данных. После каждой итерации обучающие выборки увеличиваются на некоторый коэффициент, а количество возможных кандидатов уменьшается на столько же, что приводит к гораздо более быстрому времени оценки.

Насколько быстрее? В экспериментах, которые я проводил, HalvingGridSearch был в 11 раз быстрее, чем обычный GridSearch, а HalvingRandomSearch даже в 10 раз быстрее, чем HalvingGridSearch.

19. sklearn.utils

И последнее, но не менее важное: у Sklearn есть целый ряд служебных и вспомогательных функций в подпакете sklearn.utils. Сам Sklearn использует функции этого модуля для создания всех используемых нами преобразователей и оценщиков.

Существует много полезных, таких как class_weight.compute_class_weight, estimator_html_repr, shuffle, check_X_y и т. д. Вы можете использовать их в своем собственном рабочем процессе, чтобы сделать ваш код более похожим на Sklearn, или они могут пригодиться при создании пользовательских преобразователей и оценщиков, которые вписываются в Sklearn API.

Заключение

Несмотря на то, что такие библиотеки, как CatBoost, XGBoost и LightGBM, постепенно отбирают кусок у Sklearn как у ведущей библиотеки машинного обучения, она по-прежнему остается бесценной частью стека навыков современного инженера машинного обучения.

Последовательный API, исключительный дизайн кода и возможность создавать надежные рабочие процессы ML по-прежнему делают Sklearn непревзойденным с точки зрения функциональности и гибкости. Несмотря на то, что мы можем многого добиться с помощью основ, эта статья показала, что Sklearn может предложить гораздо больше, чем кажется на первый взгляд!

Спасибо за чтение!

0
Комментарии
-3 комментариев
Раскрывать всегда