在今天的机器学习时代,各种算法和工具层出不穷,其中LightGBM凭借其出色的性能和速度,在众多机器学习算法中脱颖而出。本次实战项目,将通过一个简单但不简约的案例,展示如何使用LightGBM进行建模,并通过网格搜索进行模型优化。整个流程将包含数据探索性分析(EDA)、建模和模型优化三个主要部分。
一、数据探索性分析(EDA)
首先,我们需要对数据进行探索性分析,以了解数据的分布、特征之间的相关性以及目标变量的趋势。这一步骤对于后续的建模至关重要,因为只有深入了解数据,我们才能选择合适的特征和算法进行建模。
-
数据加载与预处理
使用Python的pandas库加载数据,并进行必要的预处理,如缺失值填充、异常值处理等。
-
数据描述性分析
通过绘制直方图、箱线图等可视化图表,我们可以直观地了解每个特征的分布情况。同时,计算特征的均值、中位数、标准差等统计量,有助于我们进一步了解数据的整体情况。
-
特征相关性分析
利用热力图或相关矩阵,我们可以分析特征之间的相关性。这对于后续的特征选择和模型构建具有重要的指导意义。
二、基于LightGBM的建模
在完成数据探索性分析后,我们将使用LightGBM进行建模。LightGBM是一种基于决策树算法的梯度提升框架,具有高效、快速、准确等优点。
-
数据划分
将数据集划分为训练集和测试集,以便在训练模型时评估其性能。
-
模型训练
使用LightGBM的API进行模型训练。我们可以调整LightGBM的参数,如学习率、树的数量、叶子节点的最小样本数等,以寻找最佳模型。
-
模型评估
通过计算准确率、召回率、F1值等指标,评估模型在测试集上的性能。同时,绘制ROC曲线和AUC值,进一步了解模型的分类性能。
三、基于网格搜索的模型优化
虽然LightGBM具有许多优秀的默认参数,但针对不同的问题和数据集,我们仍然需要调整参数以获得更好的性能。网格搜索是一种常用的参数优化方法,它通过遍历所有可能的参数组合来找到最优参数。
-
参数空间定义
根据LightGBM的文档和经验,我们定义一个包含多个参数的参数空间。这些参数可能包括学习率、树的数量、最大深度、叶子节点的最小样本数等。
-
网格搜索执行
使用scikit-learn的GridSearchCV函数进行网格搜索。该函数将自动遍历参数空间中的所有组合,并使用交叉验证评估每个组合的性能。最终,它将返回具有最佳性能的参数组合。
-
最优模型构建与评估
使用网格搜索找到的最优参数组合构建新的LightGBM模型,并在测试集上进行评估。与之前的模型相比,优化后的模型应该具有更好的性能。
四、基于LIghtGBM的贷款违约预测
实战项目使用的数据集,具体的实现代码如下:
4.1、导入相应的python库
python
import pandas as pd
import numpy as np
pd.set_option('display.max_columns', 100)
from IPython.display import display_html
import plotly_express as px
import plotly.graph_objects as go
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"] = False #解决"-"负号乱码问题
import seaborn as sns
%matplotlib inline
import missingno as ms
import gc
from datetime import datetime
from sklearn.model_selection import train_test_split, StartifiedKFold, Gr
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.decomposition import PCA
from imblearn.under_sampling import ClusterCentroids
from imblearn.over_sampling import KMeansSMOTE, SMOTE
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score, recall_score, precision_sco
from sklearn.metrics import roc_auc_score, precision_recall_curve, confu
# Classifiers
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn import tree
from pydotplus import graph_from_dot_data
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
from catboost import CatBoostClassifier
import lightgbm as lgb
import xgboost as xgb
from scipy import stats
import warnings
warnings.filterwarnings("ignore")
4.2 导入数据查看数据情况
python
df = pd.read_csv("random_data.csv")
df.columns
# 缺省值情况
df.isnull().sum()
df["History_Default_Times"].value_counts() # 历史违约次数统计:
df["Sex"].value_counts() # 男女人数几乎相同,很均衡。
df["Default"].value_counts() # 目标变量是否违约的人数对比
df[df["History_Default_Times"] == 2] # 需要注意的是:历史违约次数大于0,不代表一定是违约客户。比如历史违约次数为2,最终是否违约的客户两种情况都有。
4.3 数据简单的可视化
python
# 是否违约的客户收入存在差异:
fig = px.violin(df, x="Default",y="Income")
fig.show()
# 基于seaborn绘制密度图:
sns.displot(data=df,x="Income",hue="Default",kind="kde")
plt.show() # 可以看到在低收入和高收入人群中容易发生违约。
fig = px.violin(df, x="Default",y="Age")
fig.show()
sns.displot(data=df,x="Age",hue="Default",kind="kde")
plt.show() # 可以看到是是否违约客户的年龄段分布是一致的。
4.4 数据集合切分
python
# 提取特征和目标变量
X = df.drop(columns="Default")
Y = df["Default"]
# 划分训练集和测试集数据
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=42)
4.5 模型训练
python
from lightgbm import LGBMClassifier
model = LGBMClassifier()
model.fit(X_train, y_train) # 模型训练
4.6 模型预测
python
y_pred = model.predict(X_test)
y_pred
4.7 模型评估
python
### 1、对比测试集中的实际值和预测值:
predict_true = pd.DataFrame()
predict_true["预测值"] = list(y_pred)
predict_true["实际值"] = list(y_test)
predict_true
# 模型在测试集上的准确率
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_pred, y_test)
accuracy
# ROC-AUC曲线的绘制:
y_pred_proba = model.predict_proba(X_test)
y_pred_proba[:5]
from sklearn.metrics import roc_curve # ROC-AUC曲线
fpr, tpr, thres = roc_curve(y_test, y_pred_proba[:,1])
plt.plot(fpr, tpr)
plt.title("ROC_AUC Curve of Default")
plt.show()
# 3、查看具体的AUC值:
from sklearn.metrics import roc_auc_score
score = roc_auc_score(y_test, y_pred_proba[:,1])
score
4.8 特征重要度
python
model.feature_importances_
model.feature_name_
features_df = pd.DataFrame({"features": model.feature_name_,"importances": model.feature_importances_})
features_df
4.9 模型调优
python
# 基于网格搜索的模型调优:
from sklearn.model_selection import GridSearchCV
# 设定待搜索的参数及其取值范围:
parameters = {"num_leaves": [10, 15, 13],
"n_estimators":[10,20,30],
"learning_rate":[0.05,0.1,0.2]
}
model = LGBMClassifier() # 基础模型实例化
# 定义搜索实例化对象
grid_search = GridSearchCV(model, # 基础模型
parameters, # 搜索参数
scoring="roc_auc", # 评价指标
cv=5 # 交叉验证5次
)
grid_search.fit(X_train, y_train) # 模型训练
4.10 K折交叉验证
python
import os
import gc
import math
import pandas as pd
import numpy as np
import lightgbm as lgb
import xgboost as xgb
from catboost import CatBoostRegressor
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import log_loss
from sklearn.model_selection import train_test_split
from tqdm import tqdm
import matplotlib.pyplot as plt
import time
import warnings
warnings.filterwarnings('ignore')
def cv_model(clf, train_x, train_y, test_x, seed=2024):
# 使用K折交叉验证训练和验证模型
folds = 5
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)
# 初始化oof预测和测试集预测
oof = np.zeros(train_x.shape[0])
test_predict = np.zeros(test_x.shape[0])
cv_scores = []
# KFold交叉验证
for i, (train_index, valid_index) in enumerate(kf.split(train_x, train_y)):
print('************************************ {} ************************************'.format(str(i+1)))
trn_x, trn_y, val_x, val_y = train_x.iloc[train_index], train_y[train_index], train_x.iloc[valid_index], train_y[valid_index]
# 转换数据为lightgbm数据格式
train_matrix = clf.Dataset(trn_x, label=trn_y)
valid_matrix = clf.Dataset(val_x, label=val_y)
# 定义lightgbm参数
params = {
'boosting_type': 'gbdt', # GBDT算法为基础
'objective': 'multiclass', # 多分类任务
'num_class': 4, # 设置多分类问题的类别个数
'num_leaves': 2 ** 5, # 指定叶子的个数,默认值为31,大会更准,但可能过拟合。最大不能超过2^max_depth
# 构建弱学习器,对特征随机采样的比例,默认值为1,可以防止过拟合,每次迭代中随机选择80%的参数来建树
'feature_fraction': 0.8,
'bagging_fraction': 0.8, # 每次迭代时用的数据比例,用于加快训练速度和减小过拟合
'bagging_freq': 4, # 表示bagging(采样)的频率,0意味着没有使用bagging ,k意味着每k轮迭代进行一次bagging
'learning_rate': 0.025,
'seed': seed,
# 使用线程数,一般设置成-1,使用所有线程。这个参数用来控制最大并行的线程数,如果你希望取得所有CPU的核,那么你就不用管它。
'nthread': 28,
'n_jobs':24, # 使用多少个线性并构造模型
'verbose': -1,
'lambda_l1': 0.4, # L1正则化权重项,增加此值将使模型更加保守。
'lambda_l2': 0.5, # L2正则化权重项,增加此值将使模型更加保守
# 'device' : 'gpu'
}
# 使用训练集数据进行模型训练
model = clf.train(params,
train_set=train_matrix,
valid_sets=valid_matrix,
num_boost_round=2000,
verbose_eval=100,
early_stopping_rounds=200)
# 对验证集进行预测
val_pred = model.predict(val_x, num_iteration=model.best_iteration)
test_pred = model.predict(test_x, num_iteration=model.best_iteration)
oof[valid_index] = val_pred
test_predict += test_pred / kf.n_splits
# 计算打印当前折的分数
score = np.sqrt(mean_squared_erroe(vale_pred, val_y))
cv_scores.apped(score)
print(cv_scores)
return oof, test_predict
4.11 输出最优的参数,并在最优的参数上进行lightgbm模型的训练
python
# 输出最佳的参数组合:
dict_params = grid_search.best_params_
dict_params
# 基于最佳的参数组合建立新模型:
new_model = LGBMClassifier(num_leaves=10, # 使用最佳参数
n_estimators=30,
learning_rate=0.05
)