На прошлой неделе мы создали простую классификационную модель и настроили ее, чтобы предсказать, будет ли пациент страдать от сердечной недостаточности. Без особых изменений модель правильно предсказала возникновение сердечной недостаточности в 83% случаев. Это, безусловно, хорошее начало, но мы можем многое сделать, чтобы улучшить этот показатель. В этом посте мы попытаемся улучшить оценку модели, выполнив шаг, известный как предварительная обработка.

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

В этом конкретном случае у нас есть два типа данных:

Числовые данные интервала:

['age',
 'creatinine_phosphokinase',
 'ejection_fraction',
 'platelets',
 'serum_creatinine',
 'serum_sodium',
 'time']

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

Номинальные категориальные данные:

['anaemia',
 'diabetes',
 'high_blood_pressure',
 'sex',
 'smoking']

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

Кодировка:

Категориальные данные в необработанном виде почти всегда хранятся в виде строки. К сожалению, большинство моделей машинного обучения не могут понимать строки (существует ветвь машинного обучения, называемая НЛП, которая пытается решить именно эту проблему, но это тема для другого поста). Чтобы модель машинного обучения понимала категориальный тип данных, его необходимо закодировать.

Для номинальных категориальных данных кодирование известно как одно горячее кодирование:

Для порядковых категориальных данных кодировка известна как порядковая кодировка:

Ниже приведен простой скрипт Python, который использует библиотеку обучения scikit для кодирования функций, представляющих собой категориальные данные:

from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
from sklearn.compose import ColumnTransformer
import pandas as pd
import numpy as np
data = pd.read_csv(C:\some_file_path\data.csv)
X = data.drop('target_variable', axis=1)
#Collecting columns and storing them in a new data frame if they #aren't numbers (which generally indicates categorical data):
X_categorical = df.select_dtypes(exclude='number')
#At this point the data frame of categorical features will have to be #inspected to determine which columns are ordinal and which are #nominal. Once this is done, they need to be separated manually into #two additional data frames:
X_cat_nominal = X_categorical[[nominal_col_1, ..., nominal_col_n]]
X_cat_ordinal = X_categorical[[ordinal_col_1, ..., ordinal_col_n]]
#ColumnTransformer, OneHotEncoder, and Ordinal Encoder is now used #to encode the columns:
ord_enc = OrdinalEncoder()
one_hot_enc = OneHotEncoder()
preprocessor = ColumnTransformer(transformers = [
                     ('ordinal_encoder',
                      ord_enc,
                      X_cat_ordinal.columns.to_list()
                     ),
                     ('nominal_encoder,
                      one_hot_enc,
                      X_cat_nominal.columns.to_list()
                     )])
X_categorical_encoded = preprocessor.fit_transform(X_categorical)

Масштабирование/Нормализация/Стандартизация:

В зависимости от типа используемой модели числовые данные должны быть преобразованы.

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

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

Стандартизация. Данные преобразуются таким образом, чтобы распределение набора данных имело среднее значение 0 и стандартное отклонение 1 (т. е. могло быть описано стандартным нормальным распределением). Многие модели машинного обучения требуют стандартизации. Примеры включают SVM, нейронные сети и логистическую регрессию.

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

from sklearn.preprocessing import StandardScaler, RobustScaler,\ Normalizer, MinMaxScaler, MaxAbsScaler
import pandas as pd
import numpy as np
data = pd.read_csv(C:\some_file_path\data.csv)
X = data.drop('target_variable', axis=1)
#Collecting columns and storing them in a new data frame if they #contain numbers (indicating numerical data):
X_numerical = df.select_dtypes(include='number')
ss = StandardScaler()
norm = Normalizer()
rs = RobustScaler()
minmax = MinMaxScaler()
maxabs = MaxAbsScaler()
def transformation_function(transformer):
   return pd.DataFrame(transformer.fit_transform(X_numerical))

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

rf = RandomForestClassifier()
gb = GradientBoostingClassifier()
rf_param_grid = {
    'max_depth':range(2,7),
    'n_estimators':range(10,30)
}
gb_param_grid = {
    'loss':['deviance','exponential'],
    'max_depth':range(2,7),
    'max_features':['sqrt','log2']
}
def model_fitter(model):
    model.fit(X_train, y_train)
    print('Training Score: {}'.format(model.score(X_train, y_train)))
    y_pred = model.predict(X_test)
    print('Test Score {}:'.format(accuracy_score(y_test, y_pred)))
    
def grid_search(model,param_grid):
    grid_search_rf = GridSearchCV(
        estimator=model,
        param_grid=param_grid,
        scoring='accuracy',
        n_jobs=-1,
        cv=5
    )
    grid_search_rf.fit(
        X_train,
        y_train
    )
    print('Best Parameters were: {}'.format(grid_search_rf.best_params_))
    print('Best CrossVal Score was: {}'.format(grid_search_rf.best_score_))

После повторного запуска модели с предварительно обработанными данными были получены следующие оценки:

После кодирования и масштабирования данных мы повысили точность модели на 3,66%. Совершенно очевидно, что предварительная обработка — это простой, но важный шаг в процессе моделирования, который может существенно повлиять на производительность модели.