使用 LGBM 等模型预测信用卡潜在客户
关于数据集
有一家名为Happy Customer Bank (快乐客户银行) 的银行,是一家中型私人银行,经营各类银行产品,如储蓄账户、往来账户、投资产品、信贷产品等。
该银行还向现有客户交叉销售产品,为此他们使用不同类型的通信方式,如电话、电子邮件、网上银行推荐、手机银行等。
在这种情况下,Happy Customer Bank 希望向现有客户交叉销售其信用卡。该银行已经确定了一组有资格使用这些信用卡的客户。
银行希望确定对推荐的信用卡表现出更高意向的客户。
该数据集主要包括:
客户详细信息(gender, age, region, etc)他/她与银行的关系详情(Channel_Code、Vintage、Avg_Asset_Value, etc)
在这里,我们的任务是构建一个能够识别对信用卡感兴趣的客户的模型。
导入库
导入必要的库,例如用于线性代数的 NumPy、用于数据处理的 Pandas、Seaborn 和用于数据可视化的 Matplotlib。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
加载数据集
df_train=pd.read_csv("dataset/train_s3TEQDk.csv")
df_train["source"]="train"
df_test=pd.read_csv("dataset/test_mSzZ8RL.csv")
df_test["source"]="test"
df=pd.concat([df_train,df_test],
ignore_index=True)
df.head()
检查和清洗数据集
加载数据集后,下一步是检查有关数据集的信息并清理数据集,包括检查形状、数据类型、唯一值、缺失值和异常值等。
检查形状df.shape
在我们的数据集中,合并训练和测试文件后,我们有 351037 行,具有 12 个特征。
检查唯一值df.nunique()
ID 351037
Gender 2
Age 63
Region_Code 35
Occupation 4
Channel_Code 4
Vintage 66
Credit_Product 2
Avg_Account_Balance 162137
Is_Active 2
Is_Lead 2
source 2
dtype: int64检查缺失值df.isnull().sum()
ID 0
Gender 0
Age 0
Region_Code 0
Occupation 0
Channel_Code 0
Vintage 0
Credit_Product 41847
Avg_Account_Balance 0
Is_Active 0
Is_Lead 105312
source 0
Credit_Product 特征中存在不少空值。
现在我们使用 fillna 方法来填充数据集中的空值。
#填充空值
df[Credit_Product]= df[Credit_Product].fillna("NA")
我们删除了数据集中存在的所有空值。
检查数据类型
接下来我们必须检查特征的数据类型。
df.info()
RangeIndex: 351037 entries, 0 to 351036
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 ID 351037 non-null object
1 Gender 351037 non-null object
2 Age 351037 non-null int64
3 Region_Code 351037 non-null object
4 Occupation 351037 non-null object
5 Channel_Code 351037 non-null object
6 Vintage 351037 non-null int64
7 Credit_Product 351037 non-null object
8 Avg_Account_Balance 351037 non-null int64
9 Is_Active 351037 non-null object
10 Is_Lead 245725 non-null float64
11 source 351037 non-null object
dtypes: float64(1), int64(3), object(8)
memory usage: 32.1 MB
观察得到:
一些分类特征需要在数值数据类型中进行更改。在这里,我们发现 Is_Active 特征有两个值,即 Yes 和 No。因此,我们必须将这些值转换为 float 数据类型。
将 Is_Active 列中的 Yes 更改为 1 并将 No 更改为 0 以将数据转换为浮点数。
df["Is_Active"].replace(["Yes","No"]
,[1,0], inplace=True)
df[Is_Active] = df[Is_Active].astype(float)
df.head()
现在,为了将所有分类列更改为数字形式,我们使用标签编码。我们先简要了解标签编码到底是什么。
标签编码: 标签编码是指将标签转换为数字形式,以便将其转换为机器可读形式。它是一种用于处理分类变量的流行编码技术。
接下来使用标签编码器。
#创建分类列列表
cat_col=[Gender, Region_Code,
Occupation,Channel_Code,
Credit_Product]
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
for col in cat_col:
df[col]= le.fit_transform(df[col])
df_2= df
df_2.head()
此时,我们可以删除不相关且对我们的数据集没有影响的特征。这里我们有两列要删除,即"ID"和"source"。让我们检查一下最新的输出。
至此,我们观察到所有数据都是数字。
数据可视化
为了更加清晰地分析数据集,数据可视化是一个不可或缺的步骤。
单变量分析
首先,我们绘制了 dist计数图 以了解数据的分布。
年龄特征分布密度图
观察得到:
在年龄分布略偏向左侧,即“正偏态”。在这里,我们看到一个峰值年龄组在 20 到 40 岁之间,该年龄段更加年轻,而另一个峰值年龄组在 40 到 60 岁之间。除此之外,40 到 60 岁之间的人更有优势。因此,这可能与"Vintage"变量相关联,该变量对于较高年龄组更明显。
性别特征的计数图
观察得到:
数据集中存在更多男性客户。但是,在决定谁拥有更好的决策权时,客户的性别并不重要。
目标变量计数图
本案例中的目标变量为 Is_Lead 特征。
观察得到:
该图显示数据高度不平衡,在应用不同算法之前进行需要对数据集进行平衡处理。为了平衡数据集,下面的步骤中将会使用欠采样技术。
此处可以参考:机器学习中样本不平衡,怎么办?
双变量分析
接下来做一些双变量分析,以理解不同列之间的关系。
"职业"和"客户"
观察得到:
我们观察到自由职业客户不太可能办理信用卡。而企业家(尽管有限)最有可能办理信用卡。
近3个月内不同"客户的职业"的"客户活跃度"
观察得到:
在过去3个月里,与企业家相比,活跃客户更多地来自工薪阶层、个体经营者和其他人群。与 “活跃” 的客户相比,过去3个月内不活跃的客户相当多。与 “非活跃” 客户相比,“活跃” 客户的潜在客户比例更高。
数据预处理
正如前所述,该数据集目标变量是不平衡的,需要进行平衡处理以建立有效的建模。
因此我们采用欠采样方法来处理平衡数据集。
接下来首先导入库,再将少数类和多数类分开。
from sklearn.utils import resample
# 将少数类和多数类分开
df_majority = df_1[df_1[Is_Lead]==0]
df_minority = df_1[df_1[Is_Lead]==1]
print("多数类值为", len(df_majority))
print("少数类值是", len(df_minority))
print("两个类的比例是", len(df_majority)/len(df_minority))
观察得到:
多数类值为187437,少数类值为58288,两个类的比率为3.2。
现在,需要将少数类与过采样的多数类结合起来。
# 欠采样多数类
df_majority_undersampled = resample(df_majority,
replace=True,
n_samples=len(df_minority),
random_state=0)
# 结合少数类和过采样的多数类
df_undersampled = pd.concat([df_minority,
df_majority_undersampled])
df_undersampled[Is_Lead].value_counts()
df_1=df_undersampled
在此之后,我们必须计算新的类值计数。
# 显示新的类值计数
print("欠采样类值计数为:", len(df_undersampled))
print("两个类的比例为:",
len(df_undersampled[df_undersampled["Is_Lead"]==0]
)/len(df_undersampled[df_undersampled["Is_Lead"]==1]))
观察得到:
欠采样类值计数为 126800。两个类的比率为 1.0。
此时需要将特征变量与目标变量分开,并拆分训练集及测试集。
# 删除目标变量
xc = df_1.drop(columns=[Is_Lead])
yc = df_1[["Is_Lead"]]
现在,我在这里使用 Standard Scaler 对x的值进行标准化以使数据呈正态分布。
sc = StandardScaler()
#Standard Scaler的实例
df_xc = pd.DataFrame(sc.fit_transform(xc),columns=xc.columns)
df_xc
分类模型建立
导入分类建模所需的库#Importing necessary libraries
from sklearn import metrics
from scipy.stats import zscore
from sklearn.preprocessing import LabelEncoder,StandardScaler
from sklearn.model_selection import train_test_split,GridSearchCV
from sklearn.decomposition import PCA
from sklearn.metrics import precision_score, recall_score, confusion_matrix, f1_score, roc_auc_score, roc_curve
from sklearn.metrics import accuracy_score,classification_report,confusion_matrix,roc_auc_score,roc_curve
from sklearn.metrics import auc
from sklearn.metrics import plot_roc_curve
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import MultinomialNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier,GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
from sklearn.naive_bayes import GaussianNB
#Import warnings
import warnings
warnings.filterwarnings(ignore)评价指标及分类模型确定
本节我们使用多个分类模型并计算了精确度、召回率、ROC_AUC 分数和 F1 分数等指标。
本案例中使用的模型是:
逻辑回归分类器随机森林分类器决策树分类器高斯贝叶斯分类器定义函数以寻找模型的拟合性#defining a function to find fit of the model
def max_accuracy_scr(names,model_c,df_xc,yc):
accuracy_scr_max = 0
roc_scr_max=0
train_xc,test_xc,train_yc,test_yc = train_test_split(df_xc,yc,
random_state = 42,test_size = 0.2,stratify = yc)
model_c.fit(train_xc,train_yc)
pred = model_c.predict_proba(test_xc)[:, 1]
roc_score = roc_auc_score(test_yc, pred)
accuracy_scr = accuracy_score(test_yc,model_c.predict(test_xc))
if roc_score