дай код для сохранения модели и геипер параметров, вообщем чтобы сохранить все наработки кода,
код:


import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.model_selection import train_test_split, GridSearchCV
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score, roc_auc_score, roc_curve
from sklearn.compose import ColumnTransformer
import matplotlib.pyplot as plt

class BankMarketingModel:
    def __init__(self):
        self.preprocessor = None
        self.model = None
    
    def preprocess_data(self, data):
        # Обработка пропущенных или "unknown" значений
        data.replace('unknown', 'Unknown', inplace=True)
        
        # Разделение признаков на категориальные и числовые
        categorical_columns = ['job', 'marital', 'education', 'default', 'housing', 
                               'loan', 'contact', 'month', 'poutcome']
        numerical_columns = ['age', 'balance', 'day', 'duration', 'campaign', 'pdays', 'previous']
        target = 'y'
        
        # Кодирование категориальных признаков и нормализация числовых
        self.preprocessor = ColumnTransformer(
            transformers=[
                ('num', StandardScaler(), numerical_columns),
                ('cat', OneHotEncoder(drop='first', sparse_output=False), categorical_columns)
            ]
        )
        
        # Разделение данных на признаки (X) и целевую переменную (y)
        X = data.drop(target, axis=1)
        y = data[target].map({'no': 0, 'yes': 1})  # Преобразуем целевую переменную в бинарный формат
        
        return X, y
    
    def train(self, X_train, y_train):
        # Применяем предварительную обработку данных
        X_train_processed = self.preprocessor.fit_transform(X_train)
        
        # Балансировка классов с использованием SMOTE
        smote = SMOTE(random_state=42)
        X_train_res, y_train_res = smote.fit_resample(X_train_processed, y_train)
        
        # Инициализация модели с балансировкой классов
        rf = RandomForestClassifier(random_state=42, class_weight='balanced')
        
        # Тюнинг гиперпараметров с использованием GridSearchCV
        param_grid = {
            'n_estimators': [100, 200, 300],
            'max_depth': [None, 10, 20, 30],
            'min_samples_split': [2, 5, 10],
            'min_samples_leaf': [1, 2, 4],
            'max_features': ['auto', 'sqrt', 'log2']
        }
        
        grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=3, scoring='roc_auc', n_jobs=-1)
        grid_search.fit(X_train_res, y_train_res)
        
        # Лучшая модель
        self.model = grid_search.best_estimator_
    
    def predict(self, X_test, threshold=0.5):
        # Обработка тестовой выборки
        X_test_processed = self.preprocessor.transform(X_test)
        
        # Прогнозирование вероятностей на тестовой выборке
        y_pred_proba = self.model.predict_proba(X_test_processed)[:, 1]
        y_pred = (y_pred_proba >= threshold).astype(int)
        
        return y_pred, y_pred_proba
    
    def evaluate(self, y_test, y_pred, y_pred_proba):
        # Оценка модели
        print("\nAccuracy:", accuracy_score(y_test, y_pred))
        print("\nConfusion Matrix:\n", confusion_matrix(y_test, y_pred))
        print("\nClassification Report:\n", classification_report(y_test, y_pred))
        
        # Расчет AUC и ROC-кривой
        auc = roc_auc_score(y_test, y_pred_proba)
        fpr, tpr, _ = roc_curve(y_test, y_pred_proba)
        
        print("\nAUC Score:", auc)
        
        plt.figure()
        plt.plot(fpr, tpr, color='blue', label=f'ROC curve (area = {auc:.2f})')
        plt.plot([0, 1], [0, 1], color='red', linestyle='--')
        plt.xlabel('False Positive Rate')
        plt.ylabel('True Positive Rate')
        plt.title('ROC Curve')
        plt.legend(loc="lower right")
        plt.show()

# Пример использования:
file_path = 'bank.csv'
data = pd.read_csv(file_path)

# Разделение данных
model = BankMarketingModel()
X, y = model.preprocess_data(data)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Обучение модели
model.train(X_train, y_train)

# Прогнозирование и оценка
y_pred, y_pred_proba = model.predict(X_test, threshold=0.4)  # Попробуем порог 0.4 для повышения recall
model.evaluate(y_test, y_pred, y_pred_proba)