机器学习投票分类
前阵子客户有个小需求是用机器学习建模分类模型,并用投票分类提升分类效果。给出的数据集已经上传到资源链接中。
这组数据应该是烟草烘(干)工艺的在线监测记录,也就是“烘丝机”或“烟丝干燥线”上每隔20分钟自动采样的实时参数。分类的label是status,一共是[0,1,2,3,4,5,6]七个类别。
首先构建数据集:
# 读取 CSV 文件
df = pd.read_csv('200812192633-SY-B-1-C-87.csv')# 假设除了 STATUS 外其他列都是特征,根据实际情况调整
X = df.drop(['UPLOAD_TIME','STATUS', 'BATCH_ID'], axis=1)X = X.valuesy = df['STATUS']# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
分类的label分布情况如下图所示:
XGB模型建模
# 初始化 XGB分类器
xgb_clf = XGBClassifier(objective='multi:softmax', # 多分类任务num_class=len(df['STATUS'].unique()), # 类别数random_state=42
)# 定义更详细的参数网格
param_distributions_xgb = {'n_estimators': [50, 100, 200, 300, 400], # 增加了更多的树的数量'max_depth': [3, 5, 7, 9, 11], # 增加了树的最大深度范围'learning_rate': [0.001, 0.01, 0.1, 0.2, 0.3], # 增加了更多的学习率选项'subsample': [0.7, 0.8, 0.9, 1.0], # 增加了子采样参数'colsample_bytree': [0.7, 0.8, 0.9, 1.0], # 增加了列采样参数'gamma': [0, 0.1, 0.2, 0.3], # 增加了 gamma 参数,用于控制是否后剪枝'min_child_weight': [1, 2, 3, 4, 5] # 增加了子节点的最小样本权重和
}# 实例化GridSearchCV对象
grid_search_xgb = RandomizedSearchCV(estimator=xgb_clf,param_distributions=param_distributions_xgb,n_iter=100,cv=3,scoring='accuracy',n_jobs=-1,verbose=1
)grid_search_xgb.fit(X_train, np.ravel(y_train)) # np.ravel 用于将 y_train 转为一维数组# 输出最佳参数和最佳准确率
print(f"XGB 最佳参数: {grid_search_xgb.best_params_}")
print(f"XGB 最佳交叉验证准确率: {grid_search_xgb.best_score_:.4f}")# 使用最佳参数重新训练模型
best_xgb = grid_search_xgb.best_estimator_# 预测验证集
y_pred = best_xgb.predict(X_test)# 保存模型
joblib.dump(best_xgb, 'xgb_model.joblib')
print("\n模型已保存为 'xgb_model.joblib'")
分类结果如图所示:
绘制混淆矩阵
# 可视化混淆矩阵
conf_matrix = confusion_matrix(y_test, y_pred)# 使用 seaborn 绘制热图
plt.figure(figsize=(12, 10))
sns.heatmap(conf_matrix, annot=True, fmt='d', cmap='Blues', xticklabels=np.arange(len(df['STATUS'].unique())), yticklabels=np.arange(len(df['STATUS'].unique())))
plt.title('Confusion Matrix')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.tight_layout()
LGBM模型建模
与XGB模型类似
# 初始化 LGBM 分类器
lgbm_clf = LGBMClassifier(objective='multiclass', # 多分类任务num_class=len(df['STATUS'].unique()), # 类别数random_state=42
)# 定义更详细的参数分布
param_distributions_lgbm = {'n_estimators': [50, 100, 200, 300, 400], # 树的数量'max_depth': [-1, 5, 10, 15, 20], # -1 表示无限制'learning_rate': [0.001, 0.01, 0.1, 0.2, 0.3], # 学习率'num_leaves': [15, 31, 63, 127, 255], # 叶子数'subsample': [0.7, 0.8, 0.9, 1.0], # 子采样比例'colsample_bytree': [0.7, 0.8, 0.9, 1.0], # 列采样比例'reg_alpha': [0, 0.1, 0.3, 0.5], # L1 正则化参数'reg_lambda': [0, 0.1, 0.3, 0.5] # L2 正则化参数
}# 实例化 RandomizedSearchCV 对象
random_search_lgbm = RandomizedSearchCV(estimator=lgbm_clf,param_distributions=param_distributions_lgbm,n_iter=100, # 迭代次数,可以调整cv=3,scoring='accuracy',n_jobs=-1,verbose=1,random_state=42
)random_search_lgbm.fit(X_train, np.ravel(y_train)) # np.ravel 将 y_train 转为一维数组# 输出最佳参数和最佳准确率
print(f"LGBM 最佳参数: {random_search_lgbm.best_params_}")
print(f"LGBM 最佳交叉验证准确率: {random_search_lgbm.best_score_:.4f}")# 使用最佳参数重新训练模型
best_lgbm = random_search_lgbm.best_estimator_# 预测验证集
y_pred = best_lgbm.predict(X_test)# 保存模型
joblib.dump(best_lgbm, 'lgbm_model.joblib')
print("\n模型已保存为 'lgbm_model.joblib'")
接下来用两个模型进行投票分类
硬投票
# 假设 best_xgb 和 best_lgbm 是已经训练好的 XGB 和 LGBM 模型
voting_clf = VotingClassifier(estimators=[('xgb', best_xgb),('lgbm', best_lgbm)],voting='hard' # 硬投票
)# 训练投票分类器
voting_clf.fit(X_train, y_train)# 预测
y_pred = voting_clf.predict(X_test)
软投票
# 确保 XGB 和 LGBM 模型在初始化时支持概率预测
best_xgb.set_params(objective='multi:softprob') # XGB 需要设置 objective 为 'multi:softprob' 才能输出概率
best_lgbm.set_params(objective='multiclass') # LGBM 默认支持概率预测voting_clf = VotingClassifier(estimators=[('xgb', best_xgb),('lgbm', best_lgbm)],voting='soft' # 软投票
)# 训练投票分类器
voting_clf.fit(X_train, y_train)
加权投票
# 假设根据验证集上的表现,XGB 模型的权重为 0.6,LGBM 模型的权重为 0.4
weights = [0.8, 0.2]voting_clf = VotingClassifier(estimators=[('xgb', best_xgb),('lgbm', best_lgbm)],voting='soft', # 软投票weights=weights # 设置权重
)# 训练投票分类器
voting_clf.fit(X_train, y_train)# 预测
y_pred = voting_clf.predict(X_test)