0 前言
0.1 项目背景
现存在数据集文件《信用卡客户流失数据集.csv》(由于文件内容很长,所以添加到了本文附件中,不放在本文正文中影响本文的阅读),里面包含的字段信息如下表所示:
字段名称 | 字段类型 | 字段说明 |
---|---|---|
CLIENTNUM | 整型 | 客户编号,拥有帐户的客户的唯一标识符 |
Attrition_Flag | 字符型 | 目标,客户活动情况,如果帐户已关闭,则为1,否则为0 |
Customer_Age | 整型 | 客户的年龄,以年为单位 |
Gender | 字符型 | 性别,男性(M),女性(F) |
Dependent_count | 整型 | 受抚养人的数量 |
Education_Level | 字符型 | 教育资格(例如:高中(high school),大学毕业(college graduate)等) |
Marital_Status | 字符型 | 婚姻状况,已婚(Married),单身(Single),离婚(Divorced),未知(Unknown) |
Income_Category | 字符型 | 年收入,(<40K,40K-60K,60K-80K,80K-120K,>$120K,未知) |
Card_Category | 字符型 | 信用卡类型,(蓝色(Blue)、银色(Sliver)、金色(Gold)、白金(Platinum)) |
Months_on_book | 整型 | 与银行的关系期 |
Total_Relationship_Count | 整型 | 客户持有的产品数量总数 |
Months_Inactive_12_mon | 整型 | 最近12个月内没有活动的月份数 |
Contacts_Count_12_mon | 整型 | 最近12个月的联系人数 |
Credit_Limit | 浮点型 | 信用卡信用额度 |
Total_Revolving_Bal | 整型 | 信用卡总周转余额 |
Avg_Open_To_Buy | 浮点型 | 开放购买信用额度(过去12个月的平均值) |
Total_Amt_Chng_Q4_Q1 | 浮点型 | 交易金额变化(第4季度到第1季度) |
Total_Trans_Amt | 整型 | 总交易金额(过去12个月) |
Total_Trans_Ct | 整型 | 总交易数(过去12个月) |
Total_Ct_Chng_Q4_Q1 | 浮点型 | 交易计数变化(第4季度到第1季度) |
Avg_Utilization_Ratio | 浮点型 | 平均卡利用率 |
要求:构建一个模型,根据用户字段信息,能预测哪些用户可能会流失
0.2 项目分析
要实现项目需求,首先我们要从数据集文件《信用卡客户流失数据集.csv》中获取用户信息,并将做好数据的清洗、预处理以及切分工作,然后通过不同的模型做预测,找到准确率最高的模型,并提供满足以下输入输出的API接口:
-
输入:用户字段信息字符串
-
输出:用户是否流失的标识
下面开始介绍项目实现的操作:
1 数据处理
1.1 数据读取
首先,从CSV文件中读取用户信息数据
# 引入pandas库,提供一些数据分析的方法
import pandas as pd
# 读取《信用卡客户流失数据集.csv》文件中的数据
data = pd.read_csv(filepath_or_buffer="./信用卡客户流失数据集.csv")
# 查看数据形状(其实就是看有多少行数据,以及每行数据有多少个列属性)
# 例:输出结果是(10134, 21),代表有10134行数据,每行数据有21个列属性
print(data.shape)
# 在Python的 Pandas 库中,info函数可以提供 DataFrame 对象的总结性信息,通常包括但不限于:
# (1)非空值数量(Non-Null Count):显示每一列非空值的个数
# (2)数据类型(Dtype):列出每一列的数据类型,例如 int64、float64、object 等
# (3)内存使用情况(Memory Usage):显示 DataFrame 所占用的内存总量
# (4)索引:如果设置了索引,会显示索引的信息
# (5)列信息:如果 DataFrame 有列信息,也会显示出来
# 这个函数对于快速了解数据集的结构和数据类型非常有用,特别是在数据清洗和预处理阶段
# 注意事项:
# (1)如果 DataFrame 非常大,则data.info()默认只显示每列的非空值计数和数据类型
# 此时,若要查看更多的细节,则需要传递参数 verbose=True
# (2)如果 DataFrame 有很多列,输出可能会被截断
# 此时,若要显示所有列的信息,则需要传递参数 null_counts=True
print(data.info())
# 类似linux系统查看大文件的内容的命令,我们可以用head和tail函数查看文件前几行和最后几行的内容
# 用n可以指定要查看的行数,比如:想查看前10行
print(data.head(n=10))
# 不传n,则默认查5行,比如:想查看后5行
print(data.tail())
# 此外,还可以通过sample函数随机查看n行内容
print(data.sample(n=3))
1.2 数据清洗
然后,需要对获取数据做清洗,处理重复值、缺失值、异常值、无用列
# 1、处理重复值
# 判断是否有重复,通常是要根据一个唯一值的列(id列)来进行判断,使用的是duplicated函数
# 通过数据字典,可知CLIENTNUM列表示的是客户编号,一般来讲,每个客户的编号都是唯一的,所以可以通过这个字段来判断是否存在重复数据
# 如果不传subset=["CLIENTNUM"],那么会将每一行的全部数据合并起来比较是否重复,这个和我们的实际需求不符
# 用.sum()方法计算有多少个重复的
print(data.duplicated(subset=["CLIENTNUM"]).sum())
# 删除重复值,使用的是drop_duplicates函数
# 用inplace=True参数可针对原数据进行删除,如果不用,则只是返回删除后的结果,并不会动原数据
# 注意:不是把互相重复的都进行删除,会保留重复数据出现的第一条
data.drop_duplicates(subset=["CLIENTNUM"], inplace=True)
# 查看删除重复值之后的数据信息
print(data.info())
# 2、处理缺失值(自己造数据时,可用np.nan表示缺失值)
# 判断是否缺失,通常是要将每一列的每一个数据都进行判断,使用的是isna函数
# 用.sum()方法计算有多少个缺失的
print(data.isna().sum())
# 删除缺失值,使用的是dropna函数
# 可以用how参数,指定是通过all还是any方法进行删除
# all:一行数据中每一列数据都是缺失的,才会删除此行
# how:一行数据中任何一列数据存在缺失,都会删除此行
# 用inplace=True参数可针对原数据进行删除,如果不用,则只是返回删除后的结果,并不会动原数据
data.dropna(how="any", inplace=True)
# 查看删除缺失值之后的数据信息
print(data.info())
# 3、处理异常值
# 判断是否有异常,通常是要根据实际情况来考虑,没有固定的判断函数
# 比如:
# (1)Customer_Age字段表示客户年龄,年龄一般不会小于0,且不会大于150
# (2)Months_Inactive_12_mon字段表示客户最近12个月内没有活动的月份数,月份数不会小于0,且不会大于12
# 这里将简单对Customer_Age和Months_Inactive_12_mon两字段做上述逻辑的异常判断(可能还有其他字段也值得判断,但这里暂不考虑,只介绍判断逻辑)
# 用.sum()方法计算有多少个异常的
print(((data["Customer_Age"] < 0) | (data["Customer_Age"] > 150) | (data["Months_Inactive_12_mon"] < 0) | (data["Months_Inactive_12_mon"] > 12)).sum())
# 删除异常值,可以用取反的方法
data = data[~(data["Customer_Age"] < 0) | (data["Customer_Age"] > 150) | (data["Months_Inactive_12_mon"] < 0) | (data["Months_Inactive_12_mon"] > 12)]
# 查看删除异常值之后的数据信息
print(data.info())
# 4、删除无用的列
# 删除列,使用的是drop函数