Предварительно обработайте данные правильно

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

  • Оценка качества данных
     – Поиск пропущенных значений
     – Поиск выбросов
     – Поиск несоответствия типов данных в функциях
  • Преобразование данных
     – Выбор функций/выборка
     – Агрегация данных
     – Нормализация данных
  • Feature Encoding
    -Label Encoding для порядковых переменных
    -One Hot Encoding для номинальных переменных
  • Уменьшение размерности (PCA, SVD)
  • Масштабирование функций
    -Стандартизация
    - Нормализация

Хотя такой подход абсолютно правильный, но если ваш код выглядит примерно так, дочитать этот блог до конца?

import numpy as np
import sklearn
from sklearn.preprocessing import OneHotEncoder,StandardScaler,SimpleImputer

categorical=list()
numerical=list()

for column in train_data.columns:
  if train_data[column].dtype=='object':
    categorical.append(column)
  elif train_data[column].dtype==np.number:
    numerical.append(column)

imputer=SimpleImputer(strategy='mean')
transformed_data=imputer.fit_transform(train_data[numerical])
transformed_numerical=scaler.fit_transform(train_data[numerical])
encoder=OneHotEncoder()
transformed_categorical=encoder.fit(train_data[categorical])
scaler=StandardScaler()


final_train_data=transformed_categorical+transformed_numerical

*просто абстрактный пример, не подлежащий компиляции или выполнению

Хотя этот подход будет работать, он не оптимален при работе с массивными наборами данных или в производственной среде.

Для этого вам нужен организованный рабочий процесс. Введите, scikit-learn конвейеры. Цель конвейера sklearn — собрать вместе несколько шагов.

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

Compose в scikit-learn (sklearn.compose) поможет вам его разработать.

Попробуем своими руками. А не ___ ли нам? Рассмотрим этот набор данных для воспроизведения.

#Here are allthe libraries you will be needing to play this project out

import numpy as np 
import pandas as pd 
import os
import sklearn
from sklearn import preprocessing
from sklearn.pipeline import make_pipeline
from sklearn.impute import SimpleImputer
from sklearn.compose import make_column_selector
from sklearn.compose import make_column_transformer
from sklearn.preprocessing import OrdinalEncoder
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
import time
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import StackingClassifier
from sklearn.svm import LinearSVC
from sklearn.model_selection import GridSearchCV
import warnings
warnings.filterwarnings("ignore")
#I have kept the code in relevance with kaggle for ease of use

input_paths=list()
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        input_paths+=[os.path.join(dirname, filename)]
        print(os.path.join(dirname, filename))
train_data=pd.DataFrame(pd.read_csv(input_paths[1]))
test_data=pd.DataFrame(pd.read_csv(input_paths[2]))
target=train_data['failure']
print(target.unique()) #To observe the type & distribution of our target feature
train_data=train_data.drop(columns=['failure','id'])

Выход для вышеуказанного блока кода — «0» и «1». Следовательно, целевая функция имеет дискретные значения, поэтому мы будем выполнять классификацию.

Решив, над какой проблемой мы работаем, то есть над классификацией, мы начинаем исследовательский анализ данных (EDA), проверяя неверные значения.

train_data.isna().sum()

Вы заметите, что у нас есть куча пропущенных значений в наборе данных.

(EDA предполагает внимательное наблюдение за функциями с помощью различных статистических методов и методов визуализации, но я буду ссылаться на наиболее известные методы и сосредоточу внимание блога на разработке конвейера)

Выполнение приведенного ниже блока кода также покажет, что в нашем наборе данных есть как числовые (int, float), так и категориальные (объектные) функции.

train_data.info()

Итак, давайте приступим к разработке нашего конвейера, не так ли?

make_column_selector в sklearn.compose помогает выбрать необходимые столбцы на основе их типа данных или путем сопоставления шаблона регулярного выражения с именами столбцов. Мы будем использовать его для неявного выбора числовых и категориальных признаков.

categorical_data = make_column_selector(dtype_include=object)
numerical_data=make_column_selector(dtype_include=np.number)

Теперь давайте создадим конвейер трансформатора.

#for categorical transformations
categorical_processor=OneHotEncoder(handle_unknown="ignore") 

#for numerical transformations
numerical_processor=make_pipeline(StandardScaler(), SimpleImputer(strategy="mean", add_indicator=True)) 

#combining the transformations into one common column transformer
transformer=make_column_transformer((numerical_processor,numerical_data),(categorical_processor,categorical_data))

Теперь давайте добавим модели в наш конвейер. Мы будем работать с классификаторами Random Forest и Support Vector.

'''To include everything in one pipeline at the end, we have to keep including 
the previously done work. Hence, we add our column transformer first and then
the classifier'''

rf_pipeline = make_pipeline(transformer, RandomForestClassifier(n_estimators=10, random_state=42))
svc_pipeline = make_pipeline(transformer,LinearSVC(random_state=42))

#Then we group the pipelines in a list

estimators = [
     ('rf', rf_pipeline),
     ('svc', svc_pipeline) 
]

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

sclf = StackingClassifier(estimators=estimators)

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

sclf.get_params()

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

param_grid = { 
    'svc__linearsvc__penalty': ['l1','l2'],
    'svc__linearsvc__loss': ['hinge', 'squared_hinge'],
    'svc__linearsvc__max_iter' : [10,100,1000],
    'rf__randomforestclassifier__max_depth' : [3,5,7,9],
}

clf = GridSearchCV(estimator=sclf, param_grid=param_grid, cv= 5)
clf.fit(X_train, Y_train)
print(clf.best_params_)

Теперь у нас есть лучшие значения параметров. Мы можем перенастроить наши оценщики и продолжить обучение модели.

rf_pipeline = make_pipeline(transformer, RandomForestClassifier(max_depth=3, random_state=42))
svc_pipeline = make_pipeline(transformer,LinearSVC(loss='hinge',max_iter=10,penalty='l2'))
estimators = [
     ('rf', rf_pipeline),
     ('svc', svc_pipeline) 
]

sclf=StackingClassifier(estimators=estimators)
sclf.fit_transform(X_train,Y_train)

Теперь на секунду подумайте, какой из них является нашим последним конвейером. Ответ в следующей строке. Сделанный?

Наш последний конвейер — sclf. Если вы все поняли правильно, погладьте себя. Если нет, не беспокойтесь. Просто просмотрите статью еще раз. Не стесняйтесь комментировать любые вопросы, которые у вас могут возникнуть.

Итак, это было все. Наш трубопровод готов. Чтобы получить прогнозы, вы можете просто запустить sclf.predict, а также сравнить результат с метриками оценки, которые вам нравятся.

Вы удивительны, и у вас есть это!