Kaggle竞赛——桑坦德银行客户满意度预测(一)

2023-10-21 06:40

本文主要是介绍Kaggle竞赛——桑坦德银行客户满意度预测(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

桑坦德银行客户满意度预测

  • 数据及具体目标
  • 实施流程
  • 代码实现
    • 导入数据包
    • 导入数据
    • 探索性数据分析(EDA)
      • 删除零方差特征
      • 删除稀疏特征
      • 删除重复特征
      • 判断并删除缺失值
    • 进一步探索性分析
      • 定义绘图函数
      • 目标变量的分布
      • 选取部分特征进行分析
        • 1、var3(Region)
        • 2、var15(Age)
        • 3、var38(Mortgage values)
        • 4、var36 & var21

本文所用代码及教学内容均来自于B站:讯飞AI大学堂 kaggle教学合集

从一线支持团队到最高管理层,客户满意度是衡量成功的关键。不满意的客户不会留下来,更重要的是,不满意的顾客很少在离开前表达他们的不满。
因此,桑坦德银行(Santander Bank)向 Kaggle 社区求助,希望帮助他们在早期识别不满意的客户。这样做就可以让桑坦德银行采取积极措施,来改善客户的满意度,以免为时已晚。在本次比赛中,你将使用数百个匿名特征来预测客户是否对他们的银行业务体验感到满意或不满意。

数据及具体目标

  ★ 文件描述
    train.csv - 包含目标变量的训练集
    test.csv - 不包含目标变量的测试集
    sample_submission.csv - 格式正确的示例提交文件
  ★ 数据字段
    训练集是一个包含大量数值变量的匿名数据集,匿名数据集是指所有变量丧失原有的业务含义,所有变量经过了脱敏变换,这样我们就很难从业务角度去寻找突破口。来看一下里面具体的数据字段:
    第一列是ID,中间有 369 列是经过处理的匿名变量,最后一列是目标变量 TARGET,取值为 0 表示满意的客户,取值为 1 表示不满意的客户。测试集不包含目标变量列,其余列与训练集一致,因此不再赘述。
  ★ 最终目标:对于测试集中的每个 ID,预测 TARGET 变量的概率。
  ★ 评估指标:要求用 AUC 作为评判标准,即预测概率和观察到的目标之间的 ROC 曲线下的区域面积。

实施流程

实施流程

代码实现

导入数据包

# 数据处理
import numpy as np
import pandas as pd
import random
import itertools
from scipy import stats
from scipy.sparse import hstack# 数据可视化
import matplotlib.pyplot as plt
import seaborn as sns# 特征工程
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import OneHotEncoder# 模型
from sklearn.model_selection import train_test_split
from sklearn.model_selection import RandomizedSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.calibration import CalibratedClassifierCV
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
import lightgbm as lgb
from sklearn.metrics import roc_curve, roc_auc_score, log_loss# 杂项
from tqdm import tqdm
import warningswarnings.filterwarnings("ignore")
%matplotlib inline
sns.set(palette='muted', style='whitegrid')
np.random.seed(13154)

导入数据

train = pd.read_csv('./data/santander-customer-satisfaction/train.csv')
test = pd.read_csv('./data/santander-customer-satisfaction/test.csv')
print('训练集样本数为 %i, 变量数为 %i' % (train.shape[0],train.shape[1]))
print('测试集样本数为 %i, 变量数为 %i' % (test.shape[0],test.shape[1]))

训练集和测试集的shape为:

训练集样本数为 76020, 变量数为 371
测试集样本数为 75818, 变量数为 370

我们打印出训练集的前五行:

train.head()

在这里插入图片描述

探索性数据分析(EDA)

在基于机器学习方法的数据分析过程中,我们往往要面临数据格式的不规范,单位的不统一,数据的分布不符合模型的需求等等问题。事实上,这也是在数据分析行业中人们更多的选择传统统计分析方法的原因之一。为了让数据易于被模型拟合,提升测试集的分类效果,我们需要对数据进行一定的调整。那么,应该如何选择调整策略呢?对于这种具有300多个特征的高维数据,逐个分析显然是不现实的,这里我们采取探索性数据分析方法对数据的特点进行提取。

在最初的数据处理过程中,我们有一些基本的原则是可以借鉴采纳的:
1、一个特征如果具有0方差,即对每一行记录该字段的数据都相同,那么我们认为他对目标变量是没有影响的,这样的特征我们选择删除。
2、通常来说,我们会将信息很少的特征称为稀疏特征,这里我们对“稀疏”一词作如下定义:该特征的0值的个数占到了所有值的99%。
3、判断特征是否重复。如果发现,我们仅保留其一,并删除重复特征之外的所有特征
4、删除/插补特征中带有缺失值的行

删除零方差特征

i = 0
for col in train.columns:if train[col].var() == 0:i += 1del train[col]del test[col]
print('%i 个特征具有零方差并且已被删除' % i)

删除稀疏特征

#过滤稀疏特征
#函数numpy.percentile():百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。
i=0
for col in train.columns:if np.percentile(train[col],99) == 0:i += 1del train[col]del test[col]
print('%i 个特征是稀疏的并且已被删除' % (i))

删除重复特征

#获取所有列的两两组合
#来自 itertools 模块的函数 combinations(list_name, x) 将一个列表和数字 ‘x’ 作为参数,并返回一个元组列表,每个元组的长度为 ‘x’,其中包含x个元素的所有可能组合。
# 列表中元素不能与自己结合,不包含列表中重复元素
combinations = list(itertools.combinations(train.columns,2))
print(combinations[:20])
'''
[('ID', 'var3'), ('ID', 'var15'), ('ID', 'imp_ent_var16_ult1'), ('ID', 'imp_op_var39_comer_ult1'), ('ID', 'imp_op_var39_comer_ult3'), ('ID', 'imp_op_var41_comer_ult1'), ('ID', 'imp_op_var41_comer_ult3'), ('ID', 'imp_op_var41_efect_ult1'), ('ID', 'imp_op_var41_efect_ult3'), ('ID', 'imp_op_var41_ult1'), ('ID', 'imp_op_var39_efect_ult1'), ('ID', 'imp_op_var39_efect_ult3'), ('ID', 'imp_op_var39_ult1'), ('ID', 'ind_var1_0'), ('ID', 'ind_var5_0'), ('ID', 'ind_var5'), ('ID', 'ind_var8_0'), ('ID', 'ind_var8'), ('ID', 'ind_var12_0'), ('ID', 'ind_var12')]
'''
len(combinations)#11026
#删除重复特征,保留其一
remove = []
keep = []
for f1,f2 in combinations:if (f1 not in remove) & (f2 not in remove):if train[f1].equals(train[f2]):remove.append(f1)keep.append(f2)
train.drop(remove,axis=1,inplace=True)
test.drop(remove,axis=1,inplace=True)
print('%i 个特征是重复的,并且 %i个特征已被删除' % (len(remove)*2,len(remove)))
print('其中特征 %s被删除\n特征 %s 被保留下来' % (remove,keep))
del remove
del keep
del combinations
'''
12 个特征是重复的,并且 6个特征已被删除
其中特征 ['ind_var26_0', 'ind_var25_0', 'ind_var37_0', 'num_var26_0', 'num_var25_0', 'num_var37_0']被删除
特征 ['ind_var26', 'ind_var25', 'ind_var37', 'num_var26', 'num_var25', 'num_var37'] 被保留下来
'''

判断并删除缺失值

print('训练集缺失值数量和: %i' % (train.isnull().sum().sum()))
print('测试集缺失值数量和: %i' % (test.isnull().sum().sum()))
'''训练集缺失值数量和: 0
测试集缺失值数量和: 0'''

进一步探索性分析

定义绘图函数

def countplot_target(df,h=500):''':desc  绘制目标变量的频率分布,并输出满意客户和不满意客户的数量:param h:数据标签的附加高度'''plt.figure(figsize=(5,5))plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = False#运行配置参数总的轴(axes)正常显示正负号(minus)ax = sns.countplot(x='TARGET',data=df)# ax.patches 表示条形图中的每一个矩形for p in ax.patches:height = p.get_height()ax.text(p.get_x()+p.get_width()/2,height + h,'{:1.2f}%'.format(height*100/df.shape[0]),ha='center')#指定文字显示的位置plt.title('TARGET变量的频率分布图')print('满意客户的数量为%i,不满意客户的数量为 %i' % (df[df['TARGET']==0].shape[0],df[df['TARGET']==1].shape[0]))plt.show()#定义绘制函数hisplot_comb
def hisplot_comb(col,train=train,test=test,size=(20,5),bins=20):'''绘制训练集和测试集某一特征的直方图'''plt.subplots(1,2,figsize=size)#分割界面为1行2列plt.subplot(121)plt.title('训练集特征{}的分布'.format(col))plt.ylabel('频数')plt.xlabel(col)plt.hist(train[col],bins=bins)plt.subplot(122)plt.title('测试集特征{}的分布'.format(col))plt.ylabel('频数')plt.xlabel(col)plt.hist(test[col],bins=bins)#bins:直方图的柱数,即要分的组数plt.show()def valuecounts_plot(col,train=train,test=test):'''绘制训练集和测试集特定列的频数分布折线图,并输出出现百分比最高的前5个值和最低的前5个值'''plt.subplots(1,2,figsize=(15,6))plt.subplot(121)df = train[col].value_counts().sort_index()sns.lineplot(x=df.index,y=df.values)plt.title("%s的频数分布折线图" % (col))plt.ylabel('频数')plt.subplot(122)df = test[col].value_counts().sort_index()sns.lineplot(x=df.index,y = df.values)plt.title("%s的频数分布折线图" % (col))plt.ylabel('频数')plt.tight_layout()#tight_layout会自动调整子图参数,使之填充整个图像区域。# 这是个实验特性,可能在一些情况下不工作。它仅仅检查坐标轴标签、刻度标签以及标题的部分。plt.show()print("*"*100)print("训练集特征'%s'其值占比(top 5): " % (col))print("值\t 占比%")print((train[col].value_counts()*100/train.shape[0]).iloc[:5])print("*"*100)print("训练集特征'%s'其值占比(bottom 5): " % (col))print("值\t 占比%")print((train[col].value_counts()*100/train.shape[0]).iloc[-5:])print("测试集特征'%s'其值占比(top 5): " % (col))print("值\t 占比%")print((test[col].value_counts()*100/test.shape[0]).iloc[:5])print("*"*100)print("测试集特征'%s'其值占比(bottom 5): " % (col))print("值\t 占比%")print((test[col].value_counts()*100/test.shape[0]).iloc[-5:])#定义绘图函数hisplot_target
def histplot_target(col,df=train,height=6,bins=20):''':param col: 特征:param df: 数据集:param height: 附加高度:param bins: 柱子数量:return:'''sns.FacetGrid(data=df,hue='TARGET',height=height).map(plt.hist,col,bins=bins).add_legend()plt.title('特征%s在不同目标变量下的频数分布' % (col))plt.ylabel('频数')plt.show()

目标变量的分布

满意客户的数量为73012,不满意客户的数量为 3008
在这里插入图片描述
我们可以看到数据集高度不平衡,96.04%是满意客户,只有3.96%是不满意客户

选取部分特征进行分析

1、var3(Region)

我们首先将var3的唯一值进行降序排序

np.array(sorted(train.var3.unique()))
print('共有%i个唯一值' % (len(np.array(sorted(train.var3.unique())))))

结果如下:

IDValue
0-999999
10
21
32
43

在这里,我们可以看到var3唯一值的范围踩那个0到238,例外-999999可能是缺失值。这可能表明特定客户的国籍/地区,因为208对于想桑坦德这样的全球性公司来说是一个合理的数字

这里我们发现,可能是地区的var3中出现了值为-999999的取值,我们考虑可能是系统录入数据错误,那么,这样的数据有多少呢?

print("值\t  计数")
print((train['var3'].value_counts()[:5]))
print("值\t  占比%")
print(train['var3'].value_counts()[:5]/train.shape[0]*100)
值	  		计数
2         	 74165
8            138
-999999      1169           1103           108
Name: var3, dtype: int64值	  		占比%2          97.5598538          0.181531
-999999     0.1525919          0.1446993          0.142068

这里我们输出了数量排名前五的唯一值及其占比,可以发现,-999999共有116个,占比0.15%,总体来讲对整体影响不大。因此我们可以考虑将-999999替换为出现次数最多的2,当然我们删除也可以,为了保证数据的完整性,我们选择前者。那么,替换后是否对我们目标变量的分布产生了影响呢?所以这里我们还需要查看替换后var3=2和var3≠2时训练集目标变量的分布

train['var3'].replace(-999999,2,inplace=True)
test['var3'].replace(-999999,2,inplace=True)
countplot_target(train[train['var3'] == 2],h=20)
countplot_target(train[train['var3'] != 2],h=10)

在这里插入图片描述
在这里插入图片描述
替换缺失值后基本不改变目标变量在var3中的一个分布情况

2、var15(Age)
print('var15 最小值为: %i,最大值为: %i' % (train['var15'].min(),train['var15'].max()))
#var15 最小值为: 5,最大值为: 105

var15的取值范围在5到105之间,与年龄较为相似,我们可以假定该特征为年龄进一步分析

hisplot_comb('var15')
#stats.percentileofscore  计算分数相对于分数列表的一个排名情况 第一个参数是分数列表第二个是分数
print("训练集中年龄在30岁以下的客户约占所有数据的 %.2f%%" % (stats.percentileofscore(train['var15'].values,30)))
print("测试集中年龄在30岁以下的客户约占所有数据的 %.2f%%" % (stats.percentileofscore(test['var15'].values,30)))
#训练集中年龄在30岁以下的客户约占所有数据的 56.15%
#测试集中年龄在30岁以下的客户约占所有数据的 56.58%

输出结果为:
在这里插入图片描述
由此可见,该银行的客户主要以年轻人为主,那么年轻人对银行业务的满意程度如何呢?

ax = histplot_target('var15',bins=10)
plt.figure(figsize=(6,6))
mask = train[train['TARGET']==1]
plt.hist(mask['var15'],color='orange')
plt.title('特征var15在target=1下的频数分布')
plt.xlabel('var15')
plt.show()

结果如下:
在这里插入图片描述
在这里插入图片描述

从上图可以看出,不满意客户的年龄范围是23-102岁。所以我们可以进一步提取年龄信息,创建一个特征,用来判断客户是否小于23岁,是的话就取值为1,不是就取值为0

# 创建新特征用来判断客户是否小于23岁
for df in [train,test]:df['var15_below_23'] = np.zeros(df.shape[0],dtype=int)df.loc[df['var15'] < 23,'var15_below_23'] = 1#把var15列小于23的行记录中的var15_below_23的部分赋值为1

年龄是一个数值型变量且取值只有一百个左右,但我们面临的是一个分类问题,一个分类型变量对我们的模型拟合过程显然是更有帮助的,所以我们对var15,即年龄字段进行等距分箱操作,转化为分类变量

_,bins = pd.cut(train['var15'].values , 5,retbins=True)#retbins: 是否显示分箱的分界值。默认为False,当bins取整数时可以设置retbins=True以显示分界值,得到划分后的区间
print(_)
[(4.9, 25.0], (25.0, 45.0], (4.9, 25.0], (25.0, 45.0], (25.0, 45.0], ..., (45.0, 65.0], (25.0, 45.0], (4.9, 25.0], (4.9, 25.0], (45.0, 65.0]]

此时我们再输出变量的分布

train['var15'] = pd.cut(train['var15'].values,bins,labels=False)
test['var15'] = pd.cut(test['var15'].values,bins,labels=False)
histplot_target('var15')

结果如下:
在这里插入图片描述
在不满意的客户(图中橙色柱)中,分箱值为1的数据最多,也就是说,绝大部分不满意的客户都在1至2之间,即25到45岁

3、var38(Mortgage values)
print('最小值是 %i,最大值为 %i' % (train['var38'].min(),train['var38'].max()))
sorted(train['var38'].unique())
train.var38.value_counts()
最小值是 5163,最大值为 22034738
[5163.75,6480.66,6773.13,8290.86,8394.93,8856.21,9213.75,9342.33,9486.36...]

再查看一下唯一值的分布:

train.var38.value_counts()

在这里插入图片描述
通过上述分析我们几乎不能得到任何信息,因为一个值具有非常高的分布频率。我们将输出每个百分位值进一步探索

for i in np.arange(0,1.1,0.1):print('%i percentile : %i' % (i*100,np.quantile(train.var38.values,i)))

结果如下:

0 percentile : 5163
10 percentile : 48070
20 percentile : 61496
30 percentile : 74152
40 percentile : 88571
50 percentile : 106409
60 percentile : 117310
70 percentile : 117310
80 percentile : 132859
90 percentile : 182585
100 percentile : 22034738

我们可以看到,0百分值和10百分位值之间存在巨大差异,90百分位值和100百分位值也是相同情况
查看一下特征var38在不同目标变量下的频数分布。因为最大值太大,所以只绘制小于0.975分位数的取值分布

mask = train[train['var38'] <= np.quantile(train.var38.values,0.975)]
histplot_target('var38',df=mask,bins=20)

在这里插入图片描述
数据整体呈现右偏分布,我们可以对其进行对数变换

mask['var38'] = np.log(mask.var38).values
histplot_target('var38',df=mask,bins=20)

在这里插入图片描述
可以看到经过对数变换,分布比前者好看很多。因此,我们将对数转换应用于特征var38

for df in [train,test]:df['var38'] = np.log(df['var38']).values
histplot_target('var38',bins=20)

在这里插入图片描述

4、var36 & var21

因为特征var36和var21唯一值都比较少,所以可以不用对其转换。当然,如果觉得特征var21的唯一值比较多,也可以将出现频数小于100的值比如4500一起合并为一类,看看这样能否提高后期的预测能力

这篇关于Kaggle竞赛——桑坦德银行客户满意度预测(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/252616

相关文章

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

2024年AMC10美国数学竞赛倒计时两个月:吃透1250道真题和知识点(持续)

根据通知,2024年AMC10美国数学竞赛的报名还有两周,正式比赛还有两个月就要开始了。计划参赛的孩子们要记好时间,认真备考,最后冲刺再提高成绩。 那么如何备考2024年AMC10美国数学竞赛呢?做真题,吃透真题和背后的知识点是备考AMC8、AMC10有效的方法之一。通过做真题,可以帮助孩子找到真实竞赛的感觉,而且更加贴近比赛的内容,可以通过真题查漏补缺,更有针对性的补齐知识的短板。

2024 年高教社杯全国大学生数学建模竞赛题目——2024 年高教社杯全国大学生数学建模竞赛题目的求解

2024 年高教社杯全国大学生数学建模竞赛题目 (请先阅读“ 全国大学生数学建模竞赛论文格式规范 ”) 2024 年高教社杯全国大学生数学建模竞赛题目 随着城市化进程的加快、机动车的快速普及, 以及人们活动范围的不断扩大,城市道 路交通拥堵问题日渐严重,即使在一些非中心城市,道路交通拥堵问题也成为影响地方经 济发展和百姓幸福感的一个“痛点”,是相关部门的棘手难题之一。 考虑一个拥有知名景区

2024 年高教社杯全国大学生数学建模竞赛 C 题 农作物的种植策略 参考论文 无水印

持续更新中,2024年数学建模比赛思路代码论文都会发布到专栏内,只需订阅一次!  完整论文+代码+数据结果链接在文末!  订阅后可查看参考论文文件 第一问 1.1 问题重述 这个问题围绕的是华北山区的某乡村,在有限的耕地条件下,如何制定最优的农作物种植策略。乡村有 34 块露天耕地和 20 个大棚,种植条件包括粮食作物、蔬菜、水稻和食用菌。除了要考虑地块的面积、种植季节等,还要确保

kaggle竞赛宝典 | Mamba模型综述!

本文来源公众号“kaggle竞赛宝典”,仅用于学术分享,侵权删,干货满满。 原文链接:Mamba模型综述! 型语言模型(LLMs),成为深度学习的基石。尽管取得了令人瞩目的成就,Transformers仍面临固有的局限性,尤其是在推理时,由于注意力计算的平方复杂度,导致推理过程耗时较长。 最近,一种名为Mamba的新型架构应运而生,其灵感源自经典的状态空间模型,成为构建基础模型的有力替代方案

Tensorflow lstm实现的小说撰写预测

最近,在研究深度学习方面的知识,结合Tensorflow,完成了基于lstm的小说预测程序demo。 lstm是改进的RNN,具有长期记忆功能,相对于RNN,增加了多个门来控制输入与输出。原理方面的知识网上很多,在此,我只是将我短暂学习的tensorflow写一个预测小说的demo,如果有错误,还望大家指出。 1、将小说进行分词,去除空格,建立词汇表与id的字典,生成初始输入模型的x与y d

临床基础两手抓!这个12+神经网络模型太贪了,免疫治疗预测、通路重要性、基因重要性、通路交互作用性全部拿下!

生信碱移 IRnet介绍 用于预测病人免疫治疗反应类型的生物过程嵌入神经网络,提供通路、通路交互、基因重要性的多重可解释性评估。 临床实践中常常遇到许多复杂的问题,常见的两种是: 二分类或多分类:预测患者对治疗有无耐受(二分类)、判断患者的疾病分级(多分类); 连续数值的预测:预测癌症病人的风险、预测患者的白细胞数值水平; 尽管传统的机器学习提供了高效的建模预测与初步的特征重

【数据库实战】1_Oracle_命中关联人或黑名单或反洗钱客户

一、字段名称 1、CST_ID :客户编号 2、IDV_LGL_NM :客户姓名 3、关联方标志 RELPARTY_IND,0-否 未命中,1-是 命中 4、TBPC1010表,RSRV_FLD1_INF(备用字段)中的 第6位:黑名单标志,0无,1是。 第10位:反洗钱风险等级1-5。 反洗钱风险等级5级: 1级-低风险客户 2级-较低风险客户 3级-中风险客户 4级-较高风险客户 5级-高风

上海市计算机学会竞赛平台2024年7月月赛丙组求和问题

题目描述 给定 nn 个整数 a1,a2,…,ana1​,a2​,…,an​,请问这个序列最长有多少长的前缀,满足元素的和大于或等于 00?如果任何长度大于 00 的前缀之和都为负数,则输出 00 输入格式 第一行:单个整数表示 nn第二行:nn 个整数表示 a1,a2,…,ana1​,a2​,…,an​ 输出格式 单个整数:表示最长的前缀长度,使得前缀的和大于等于 00 数据范围