机器学习-人与机器生数据的区分模型测试 - 模型选择与微调

发布于:2025-05-19 ⋅ 阅读:(17) ⋅ 点赞:(0)

内容继续机器学习-人与机器生数据的区分模型测试

整体模型的准确率

X_train_scaled = pd.DataFrame(X_train_scaled,columns =X_train.columns )
X_test_scaled = pd.DataFrame(X_test_scaled,columns =X_test.columns)

from ngboost.distns import Bernoulli 
# 模型训练和评估
models = {
    'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
    'XGBoost': XGBClassifier(n_estimators=100, random_state=42), # 假设使用XGBoost模型,
    'Logistic Regression': LogisticRegression(random_state=42),  # 假设使用逻辑回归模型,
    'K-Nearest Neighbors': KNeighborsClassifier(),  # 假设使用KNN模型,
    'Decision Tree': DecisionTreeClassifier(random_state=42),  # 假设使用决策树模型,
    'LightGBM': LGBMClassifier(n_estimators=100, random_state=42),  # 假设使用LightGBM模型,
    'CatBoost': CatBoostClassifier(n_estimators=100, random_state=42),  # 假设使用CatBoost模型,
    #'NGBoost': NGBClassifier(Dist=Bernoulli,n_estimators=100, random_state=42)  # 假设使用NGBoost模型,
}

# 训练模型并评估
for name, model in models.items():
    model.fit(X_train_scaled, y_train)  # 训练模型
    y_pred = model.predict(X_test_scaled)  # 预测测试集
    accuracy = accuracy_score(y_test, y_pred)  # 计算准确率
    print(f"{name} Accuracy: {accuracy}")  # 打印准确率


    # 绘制混淆矩阵
    cm = confusion_matrix(y_test, y_pred)  # 计算混淆矩阵
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')  # 绘制混淆矩阵
    plt.xlabel('Predicted')  # 设置x轴标签
    plt.ylabel('True')  # 设置y轴标签
    plt.title('Confusion Matrix')  # 设置标题
    plt.show()  # 显示混淆矩阵


代码输出准确率与混淆矩阵,最后模型选择 随机森林,xgboost,lightgbm catboost四个模型。结果不一一展示。
在这里插入图片描述

输出准确率

def plot_param_impact(model_class, param_name, param_values):
    """
    绘制不同参数值对模型训练集和测试集准确率的影响曲线。

    :param model_class: 模型类,例如 RandomForestClassifier、LogisticRegression 等
    :param param_name: 要调整的参数名称,字符串类型
    :param param_values: 要测试的参数值列表
    """
    # 用于存储不同参数值下训练集的准确率
    train_acc = []
    # 用于存储不同参数值下测试集的准确率
    test_acc = []
    for value in param_values:
        # 创建模型实例,使用 ** 解包字典的方式传递当前参数值,并固定 random_state 以保证结果可复现
        model = model_class(**{param_name: value}, random_state=42)
        # 使用训练集数据对模型进行训练
        model.fit(X_train_scaled, y_train)
        # 计算模型在训练集上的准确率,并添加到 train_acc 列表中
        train_acc.append(model.score(X_train_scaled, y_train))
        # 计算模型在测试集上的准确率,并添加到 test_acc 列表中
        test_acc.append(model.score(X_test_scaled, y_test))
    
    # 创建一个新的图形,设置图形大小为 8x5 英寸
    plt.figure(figsize=(8, 5))
    # 绘制训练集准确率曲线,蓝色圆点连线
    plt.plot(param_values, train_acc, 'bo-', label='Training Accuracy')
    # 绘制测试集准确率曲线,红色方块虚线
    plt.plot(param_values, test_acc, 'rs--', label='Testing Accuracy')
    # 设置 x 轴标签为要调整的参数名称
    plt.xlabel(param_name)
    # 设置 y 轴标签为准确率
    plt.ylabel('Accuracy')
    # 设置图形标题,显示参数名称和模型类名
    plt.title(f'Impact of {param_name} on {model_class.__name__} Performance')
    # 显示图例
    plt.legend()
    # 显示网格线
    plt.grid(True)
    # 显示绘制好的图形
    plt.show()

catboost 这里需要单独处理

def catboost_plot_param_impact(model_class, param_name, param_values):
    """
    绘制不同参数值对 CatBoost 模型训练集和测试集准确率的影响曲线。

    :param model_class: 模型类,通常为 CatBoostClassifier
    :param param_name: 要调整的参数名称,字符串类型
    :param param_values: 要测试的参数值列表
    """
    # 用于存储不同参数值下训练集的准确率
    train_acc = []
    # 用于存储不同参数值下测试集的准确率
    test_acc = []
    for value in param_values:
        # 创建 CatBoost 模型实例,使用 ** 解包字典的方式传递当前参数值
        # grow_policy='Lossguide':设置树的生长策略为损失引导
        # random_state=42:固定随机种子以保证结果可复现
        # eval_metric='Accuracy':使用准确率作为评估指标
        # verbose=False:不输出训练过程信息
        model = model_class(**{param_name: value}, grow_policy='Lossguide', random_state=42,eval_metric='Accuracy',\
         verbose=False)
        # 使用训练集数据对模型进行训练
        model.fit(X_train_scaled, y_train)
        # 计算模型在训练集上的准确率,并添加到 train_acc 列表中
        train_acc.append(model.score(X_train_scaled, y_train))
        # 计算模型在测试集上的准确率,并添加到 test_acc 列表中
        test_acc.append(model.score(X_test_scaled, y_test))
    
    # 创建一个新的图形,设置图形大小为 8x5 英寸
    plt.figure(figsize=(8, 5))
    # 绘制训练集准确率曲线,蓝色圆点连线
    plt.plot(param_values, train_acc, 'bo-', label='Training Accuracy')
    # 绘制测试集准确率曲线,红色方块虚线
    plt.plot(param_values, test_acc, 'rs--', label='Testing Accuracy')
    # 设置 x 轴标签为要调整的参数名称
    plt.xlabel(param_name)
    # 设置 y 轴标签为准确率
    plt.ylabel('Accuracy')
    # 设置图形标题,显示参数名称和模型类名
    plt.title(f'Impact of {param_name} on {model_class.__name__} Performance')
    # 显示图例
    plt.legend()
    # 显示网格线
    plt.grid(True)
    # 显示绘制好的图形
    plt.show()

模型的评估与比对

#随机模型调参
def model_tuning_pipeline(
    model_class,
    default_params=None,
    param_grid=None,
    search_cv=GridSearchCV,
    search_cv_args=None,
    X_train=X_train_scaled,
    y_train=y_train,
    X_test=X_test_scaled,
    y_test=y_test,
    random_state=42,
    title_suffix=""
):
    """
    通用模型调参流水线(训练默认模型+超参数搜索+结果对比)
    
    参数:
        model_class: 模型类 (RandomForestClassifier/XGBClassifier等)
        default_params: 默认参数字典
        param_grid: 调参参数空间
        search_cv: 搜索器类 (GridSearchCV/RandomizedSearchCV)
        search_cv_args: 搜索器参数字典
        X_train: 训练特征数据(默认使用缩放后的数据)
        y_train: 训练标签数据
        X_test: 测试特征数据(默认使用缩放后的数据)
        y_test: 测试标签数据
        random_state: 随机种子
        title_suffix: 图表标题后缀
    
    返回:
        包含所有结果的字典
    """
    # 参数初始化
    default_params = default_params or {}
    search_cv_args = search_cv_args or {}
    
    # 合并随机种子参数
    merged_params = {**default_params, "random_state": random_state}
    
    # ========== 默认模型训练 ==========
    default_model = model_class(**merged_params)
    default_model.fit(X_train_scaled, y_train)
    default_train_acc = default_model.score(X_train_scaled, y_train)
    default_test_acc = model.score(X_test_scaled, y_test)

    # ========== 参数搜索优化 ==========
    # 配置搜索器参数
    param_key = "param_grid" if search_cv == GridSearchCV else "param_distributions"
    search_args = {
        "estimator": model_class(**merged_params),
        param_key: param_grid,
        **search_cv_args
    }
    
    # 执行参数搜索
    search = search_cv(**search_args)
    search.fit(X_train_scaled, y_train)
    
    # ========== 最佳模型评估 ==========
    best_model = search.best_estimator_
    tuned_train_acc = best_model.score(X_train_scaled, y_train)
    tuned_test_acc = best_model.score(X_test_scaled, y_test)

    # ========== 可视化对比 ==========
    plt.figure(figsize=(10, 6))
    labels = ['Default (Train)', 'Default (Test)', 'Tuned (Train)', 'Tuned (Test)']
    values = [default_train_acc, default_test_acc, tuned_train_acc, tuned_test_acc]
    colors = ['#1f77b4', '#ff7f0e', '#1f77b4', '#ff7f0e']  # 保持颜色一致性
    
    bars = plt.bar(labels, values, color=colors, alpha=0.7)
    plt.ylabel("Accuracy", fontsize=12)
    plt.title(f"Model Performance Comparison: {title_suffix}", fontsize=14)
    plt.ylim(min(values)-0.05, max(values)+0.05)
    
    # 添加数值标签
    for bar in bars:
        height = bar.get_height()
        plt.text(bar.get_x() + bar.get_width()/2., height,
                 f"{height:.4f}", ha="center", va="bottom")
    
    plt.grid(axis="y", linestyle="--", alpha=0.7)
    plt.tight_layout()
    plt.show()

    # 输出最佳参数
    print("="*50)
    print(f"Best parameters for {model_class.__name__}:")
    print(json.dumps(search.best_params_, indent=2))
    
    return {
        "default_model": default_model,
        "best_model": best_model,
        "performance": {
            "default_train": default_train_acc,
            "default_test": default_test_acc,
            "tuned_train": tuned_train_acc,
            "tuned_test": tuned_test_acc
        },
        "best_params": search.best_params_
    }

添加模型验证的范围

随机森林

from sklearn.model_selection import RandomizedSearchCV
num_classes = len(np.unique(y_train))

# 随机森林调参
# 调用 model_tuning_pipeline 函数对随机森林模型进行超参数调优
rf_result = model_tuning_pipeline(
    # 指定要调参的模型类为随机森林分类器
    model_class=RandomForestClassifier,
    # 设置随机森林模型的默认参数,这里设置了树的数量为 100
    default_params={"n_estimators": 100},
    # 定义要搜索的超参数空间,包含树的数量、最大深度、最小样本分割数和最大特征数
    param_grid={
        "n_estimators": [100, 200],  # 尝试不同的树的数量
        "max_depth": [None, 10, 20],  # 尝试不同的最大深度,None 表示不限制深度
        "min_samples_split": [2, 5],  # 尝试不同的最小样本分割数
        "max_features": ["sqrt", "log2"]  # 尝试不同的最大特征数选择方法
    },
    # 指定使用网格搜索进行超参数搜索
    search_cv=GridSearchCV,
    # 设置网格搜索的参数,cv 表示交叉验证的折数,n_jobs=-1 表示使用所有可用的 CPU 核心
    search_cv_args={"cv": 5, "n_jobs": -1},
    # 设置图表标题的后缀,用于标识当前调参的模型
    title_suffix="Random Forest"
)

xgboost

xgb_result = model_tuning_pipeline(
    # 指定要调优的模型类为 XGBClassifier,即 XGBoost 分类器
    model_class=XGBClassifier,
    # 设置 XGBoost 模型的默认参数
    default_params={
        # 多分类任务使用 softmax 作为目标函数
        "objective": "multi:softmax",
        # 分类的类别数量,由 num_classes 变量指定
        "num_class": num_classes
    },
    # 定义要搜索的超参数空间
    param_grid={
        # 尝试不同的树的数量
        "n_estimators": [50, 100, 150, 200],
        # 尝试不同的树的最大深度
        "max_depth": [3, 4, 5, 6],
        # 尝试不同的学习率
        "learning_rate": [0.001, 0.01, 0.1]
    },
    # 指定使用随机搜索(RandomizedSearchCV)进行超参数搜索
    search_cv=RandomizedSearchCV,
    # 设置随机搜索的参数
    search_cv_args={"n_iter": 20, "cv": 3},
    # 设置图表标题的后缀,用于标识当前调优的模型
    title_suffix="XGBoost"
)

lightgbm

# 调用 model_tuning_pipeline 函数对 LightGBM 模型进行超参数调优
lgb_result = model_tuning_pipeline(
    # 指定要调优的模型类为 LGBMClassifier,即 LightGBM 分类器
    model_class=LGBMClassifier,
    # 设置 LightGBM 模型的默认参数
    default_params={
        # 多分类任务使用 multiclass 作为目标函数
        "objective": "multiclass",
        # 分类的类别数量,由 num_classes 变量指定
        "num_class": num_classes,
        # 设置日志输出级别为 -1,即不输出日志信息
        "verbose": -1
    },
    # 定义要搜索的超参数空间
    param_grid={
        # 尝试不同的树的数量
        "n_estimators": [50, 100, 150, 200],
        # 尝试不同的树的最大深度
        "max_depth": [3, 4, 5, 6],
        # 尝试不同的学习率
        "learning_rate": [0.001, 0.01, 0.1],
        # 尝试不同的叶子节点数量
        "num_leaves": [31, 50, 100],
        # 尝试不同的叶子节点最小样本数
        "min_child_samples": [20, 50, 100]
    },
    # 指定使用随机搜索(RandomizedSearchCV)进行超参数搜索
    search_cv=RandomizedSearchCV,
    # 设置随机搜索的参数
    search_cv_args={"n_iter": 20, "cv": 3},
    # 设置图表标题的后缀,用于标识当前调优的模型
    title_suffix="LightGBM"
)

catboost


# CATBoost调参
cat_result = model_tuning_pipeline(
    model_class=CatBoostClassifier,
    default_params={
        'silent':True, 'random_state':42
       
    },
    param_grid={
    'iterations': [100, 200, 300],          # 树的数量
    'depth': [4, 6, 8],                     # 树深度
    'learning_rate': [0.01, 0.1, 0.2],      # 学习率
    'l2_leaf_reg': [1, 3, 5],               # L2正则化系数
    'border_count': [32, 64, 128],          # 特征分箱数(适用于数值特征)
    'bagging_temperature': [0, 0.5, 1.0]    # 贝叶斯自助采样强度
    },
    search_cv=RandomizedSearchCV,
    search_cv_args={"n_iter": 20, "cv": 3},
    title_suffix="CATBoost"
)

手动调参

# 随机森林
plot_param_impact(RandomForestClassifier, 'n_estimators', [10, 50, 100, 200, 300])
plot_param_impact(RandomForestClassifier, 'max_depth', [None, 5, 10, 20, 30])
plot_param_impact(RandomForestClassifier, 'min_samples_split', [2, 5, 10, 20])
plot_param_impact(RandomForestClassifier, 'max_features', ['sqrt', 'log2'])


# XGBoost
plot_param_impact(XGBClassifier, 'n_estimators', [50, 100, 150, 200,250,300])
plot_param_impact(XGBClassifier, 'max_depth', [3, 4, 5, 6,7])
plot_param_impact(XGBClassifier, 'learning_rate',  [0.1, 0.01, 0.001])
plot_param_impact(XGBClassifier, 'lambda', [0.1, 1, 5, 10])
plot_param_impact(XGBClassifier, 'alpha', [0.01, 0.01, 0.05, 1])


# lightgbm
plot_param_impact(LGBMClassifier,'num_leaves', [5, 50, 100, 200,300])         # 控制模型复杂度  
plot_param_impact(LGBMClassifier,'max_depth', [3, 5, 7, 10,12])  
plot_param_impact(LGBMClassifier,'learning_rate', [0.01, 0.1, 0.2, 0.3])  # 学习率影响
plot_param_impact(LGBMClassifier,'lambda_l1', [0, 0.01, 0.05, 0.1, 0.5])  # 正则
plot_param_impact(LGBMClassifier,'lambda_l2', [0, 0.1, 0.5, 1, 2])  # 正则
#$bagging_freq,bagging_fraction feature_fraction lambda_l2
  

# catboost
#catboost_plot_param_impact(CatBoostClassifier,'num_leaves', [15, 31, 63, 127])         # 控制模型复杂度
catboost_plot_param_impact(CatBoostClassifier,'learning_rate', [0.01, 0.1, 0.2, 0.3])  # 学习率影响
catboost_plot_param_impact(CatBoostClassifier,'max_depth', [3, 5, 7, 10])  
catboost_plot_param_impact(CatBoostClassifier,'n_estimators', [50, 100, 150, 200,300,500])  

随机调参的结果如下。数量很多不一一截图。
在这里插入图片描述
手动调参:
在这里插入图片描述
最后综合比对模型的参数效果。


网站公告

今日签到

点亮在社区的每一天
去签到