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

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

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

Сбор данных

Это первый шаг в каждом проекте машинного обучения, который включает сбор данных из различных источников или создание данных с помощью моделирования. Для этого проекта будет получен набор данных транзакций по кредитным картам от Kaggle https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud.

Предварительная обработка данных

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

import numpy as np
import pandas as pd

df = pd.read_csv('./data/creditcard.csv')

# display and describe the dataset
display(df.head(), df.describe())

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

from sklearn.model_selection import train_test_split

train_set, test_set = train_test_split(df, test_size=0.2, random_state=42)

display('Train Set', train_set.head(), 'Test Set', test_set.head())

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

Переменная предикторов (X) — это входная или независимая переменная, используемая для прогнозирования выходной или целевой переменной. Целевая переменная (y) — это выходная или зависимая переменная, которую мы пытаемся предсказать на основе входных переменных.

X = train_set.drop(columns=['Time', 'Class'])
y = train_set['Class']  
X_test = test_set.drop(columns=['Time', 'Class'])
y_test = test_set['Class']

print(f'X shape {X.shape}, y shape {y.shape} fraud cases {y.sum()} \
    X test shape {X_test.shape}, y test shape {y_test.shape} fraud on test cases {y_test.sum()} ')

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

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(X)
X = scaler.transform(X)
X_test = scaler.transform(X_test)

Исследование и анализ данных

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

import seaborn as sn
import matplotlib.pyplot as plt

sn.countplot(x=y, palette=['blue', 'red'])

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

from imblearn.over_sampling import RandomOverSampler

ros = RandomOverSampler(random_state=42)
X, y = ros.fit_resample(X, y)

sn.countplot(x=y, palette=['blue', 'red'])

Выбор модели

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

Мы будем использовать функцию cross_val_score для выбора кандидатов в нашу модель на основе их оценки F1.

from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import StratifiedKFold, RandomizedSearchCV, cross_val_score
from sklearn.ensemble import HistGradientBoostingClassifier, RandomForestClassifier, VotingClassifier, IsolationForest
def model_selection(model, X, y):
    scores = cross_val_score(model, X, y, scoring=make_scorer(f1_score), cv=8)
    # Print the scores for each fold and the mean score
    print("Cross-validation scores:", scores)
    print("Mean score:", scores.mean())

Кандидаты в модели

# HistGradientBoostingClasifier Model
gbc=HistGradientBoostingClassifier(random_state=42)
model_selection(gbc, X, y)
# RandomForestClassifier Model
rfc = RandomForestClassifier(random_state=42)
model_selection(rfc, X, y)
# MLPClassifier Model
mlpc = MLPClassifier(random_state=42)
model_selection(mlpc, X, y)

Обучение и оценка модели

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

from sklearn.base import clone 
from tqdm import tqdm 
from sklearn.metrics import confusion_matrix, mean_squared_error, make_scorer, precision_score, f1_score,  precision_recall_curve
skfold = StratifiedKFold(n_splits=8, shuffle=True, random_state=42)

def heatmap(y_test, y_preds):
    cm = confusion_matrix(y_test, y_preds)
    sn.heatmap(cm, annot=True, linewidths=.5, cmap='Blues_r', square=True, fmt='.3f')    
    plt.title(f'F1_score {f1_score(y_test, y_preds)}')
    plt.ylabel('Predicted Values')
    plt.xlabel('Actual Values')


def learning_curve(train_score, test_score):
    # This function takes an array of the mean squard error of train and test scores    
    plt.plot(np.sqrt(train_score), "r-.", linewidth=2, label="train")
    plt.plot(np.sqrt(test_score), "b-", linewidth=2, label="test")
    plt.title(f'Learning Curve')
    plt.ylabel('Mean Squared Error')
    plt.xlabel('Training Fold | Size')
    plt.legend()
    plt.show()

def trade_of_curve(y_test, y_preds):

    precision, recall, thresholds = precision_recall_curve(y_test, y_preds)
    plt.plot(recall, precision, color='blue', label='Precision-Recall Curve')
    plt.xlabel('Recall')
    plt.ylabel('Precision')
    plt.title('Precision-Recall Curve')
    plt.legend()
    plt.show()
    
    return thresholds

def train_evaluate(model, X, y):
    # train and plot learning curve
    model = clone(model)
    
    train_score , test_score =[], []
    train_f1score , test_f1score =[], []
        
    for train_fold, test_fold in tqdm(skfold.split(X, y), desc='Training folds 🤓'):

        X_train_fold, y_train_fold  = X[train_fold], y[train_fold]
        X_test_fold, y_test_fold = X[test_fold], y[test_fold]
        
        model.fit(X_train_fold, y_train_fold)
        
        train_pred = model.predict(X_train_fold)
        test_pred = model.predict(X_test_fold)
        
        train_score.append(mean_squared_error(y_train_fold, train_pred))
        test_score.append(mean_squared_error(y_test_fold, test_pred))
        train_f1score.append(f1_score(y_train_fold, train_pred))
        test_f1score.append(f1_score(y_test_fold, test_pred))
    
    print('Training completed...🥲')

    print(f'Train F1_score: {np.mean(train_f1score)}')
    print(f'Test F1_score: {np.mean(test_f1score)}')
    print(f'Train MSE: {np.mean(train_score)}')
    print(f'Test MSE: {np.mean(test_score)}')
    
    learning_curve(train_score, test_score)
    
    return model
# HistGradientBoostingClasifier Model
gbc=HistGradientBoostingClassifier(random_state=42)
gbc = train_evaluate(gbc, X, y)

prediction = gbc.predict(X_test)

heatmap(y_test, prediction)

# RandomForestClassifier Model
rfc = RandomForestClassifier(random_state=42)

rfc = train_evaluate(rfc, X, y)
prediction = rfc.predict(X_test)

heatmap(y_test, prediction)

# MLPClassifier Model
mlpc = MLPClassifier(random_state=42)

mlpc = train_evaluate(mlpc, X, y)

prediction = mlpc.predict(X_test)

heatmap(y_test, prediction)

Повышение производительности модели

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

Есть несколько способов улучшить производительность модели:

- Настройка параметров

- Регуляризация

- Ансамблевые техники

- Оценка модели

- Итерация (это повторение одного и того же шага, пока мы не получим лучшую модель)

Регуляризация

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

Разные модели имеют разные гиперпараметры регуляризации, поэтому найти лучшие гиперпараметры для регуляризации модели может быть сложно. Будем использовать RandomizedSearchCV, чтобы получить лучшие гиперпараметры регуляризации для улучшения нашей модели.

rfc_params = {
    "n_estimators": [int(x) for x in np.linspace(start = 10, stop = 1000, num = 10)],
    "max_depth": np.linspace(start = 2, stop = 10, num = 10)
}

histgradient_params = { 
    'max_iter': [int(x) for x in np.linspace(start = 100, stop = 1000, num = 10)],
    'learning_rate': np.linspace(0.01, 1, num=10),
    'max_depth': np.linspace(start = 2, stop = 10, num = 10),
    'l2_regularization': np.linspace(0.01, 1, num=10)
}

mlpc_params = {
    'max_iter': [int(x) for x in np.linspace(start = 10, stop = 200, num = 10)],
    'alpha': np.linspace(0.0001, 0.1, num=10),
    'solver': ['lbfgs', 'adam', 'sgd']
}

Настройка гиперпараметров

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

Цель настройки гиперпараметров — найти набор гиперпараметров, который обеспечит наилучшую производительность модели на проверочном или тестовом наборе.

Использование RandomizeSearchCV для автоматизации поиска гиперпараметров.

scoring = {
    'F1': make_scorer(f1_score, greater_is_better=True),
    'precision': make_scorer(precision_score, greater_is_better=True)
    # 'my_scorer': my_scorer
    }

def best_estimator(model, params, X_train, y_train):
    random_search = RandomizedSearchCV(
        model,
        param_distributions=params,
        n_iter=10,
        cv=5,
        scoring=scoring,
        refit='F1',
        n_jobs=-1,  
        random_state=42
    )

    # Fit the random search algorithm to the data
    random_search.fit(X_train, y_train)

    # Print the best hyperparameters and score
    print("Best hyperparameters:", random_search.best_params_)
    print("Validation score:", random_search.best_score_)
    
    best_estimator = random_search.best_estimator_
    
    return best_estimator

Ранняя остановка

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

# adding early stopping with warm_start hyperparameters

rfc = RandomForestClassifier(warm_start=True)
rfc = best_estimator(rfc, rfc_params, X, y)
prediction = rfc.predict(X_test)
heatmap(y_test, prediction)
# adding earlying stopping defining the early_stopping hyperparameter to True

mlpc = MLPClassifier(early_stopping=True, n_iter_no_change=10, max_iter=200)
mlpc = best_estimator(mlpc, mlpc_params, X, y)
prediction = mlpc.predict(X_test)

heatmap(y_test, prediction)

Техники ансамбля

Мы уже использовали некоторые методы/модели ансамбля, например, RandomForestClassifier и HistGradientBoostingClassifier. теперь мы добавим классификатор голосования, чтобы попытаться улучшить производительность нашей модели, объединив несколько моделей для прогнозирования. Он работает путем агрегирования прогнозов нескольких моделей и выбора наиболее частого класса в качестве окончательного прогноза, что может уменьшить переоснащение.

gbc = HistGradientBoostingClassifier(
    max_iter=100,
    max_depth=10.0,
    learning_rate=0.34,
    l2_regularization=0.56
)

rfc = RandomForestClassifier(n_estimators=340, max_depth=9.11111111111111)

mlpc = MLPClassifier(solver='lbfgs', max_iter=73, alpha=0.0001)

vc = VotingClassifier(estimators=[('gbc', gbc), ('mlpc', mlpc), ('rfc', rfc)], voting='hard')

Оценка модели

мы снова оцениваем производительность нашей модели, прежде чем внедрять ее в производство.

vc = train_evaluate(vc, X, y)

prediction = vc.predict(X_test)

heatmap(y_test, prediction)

Итерация

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

Сохранить лучшую модель

Теперь мы сохраняем нашу лучшую модель для развертывания.

import pickle
pickle.dump(vc, open('./pretrained/model.pkl', 'wb'))
pickle.dump(scaler, open('./pretrained/scaler.pkl', 'wb'))

Запуск производства

import pickle
import pandas as pd
from flask import Flask, request

model = pickle.load(open('pretrained/model.pkl'))
scaler = pickle.load(open('pretrained/scaler.pkl'))

app = Flask(__name__)

@app.route('/')
def process():
    try:
    
        csv = request.files['csv']

        features = pd.read_csv(csv),
        scaled_features = scaler.transform(features)
        preds = model.predict(scaled_features)

        return {'predictions': preds}
    
    except Exception as e:
        
        print(f"Could not process {str(e)}")
        return {"message" : "Could not process"}

if __name__ == '__main__':
    app.run() 

Заключение

В этой статье мы рассмотрели пошаговый проект сквозного машинного обучения. Найдите его на GitHub https://github.com/MuokaPWambua/CredictCardFraudDetectionMode