第2章 数据准备:Kaggle “Give Me Some Credit” 数据集
2.1 数据集背景与来源
Kaggle 上有个经典比赛叫 Give Me Some Credit,目的是通过信用历史数据预测借款人未来两年是否会发生财务危机——说白了就是违约概率。我当年入行时第一个评分卡项目就用的这个数据集,算是“入门教材”级别的存在。
数据本身很干净,训练集 15 万条,测试集 10 万条。没有缺失得太离谱,也没有太多乱码。你想想看,这种公开数据集最大的好处就是省了数据采集的功夫,可以直接用来练手。
核心指标:训练集样本数 150,000,测试集样本数 101,503,共 12 个字段。
2.2 数据获取
Kaggle 上直接下载 cs-training.csv 和 cs-test.csv 两个文件。格式是标准的 CSV,逗号分隔。我个人习惯把文件放在项目根目录下的 data/raw/ 文件夹里,方便后续管理。
嗯,这里要注意:下载下来的是一个 zip 包,里面除了 CSV 还有一本数据字典(DataDict.pdf)。别偷懒,那本字典我建议你打开看一眼——字段含义都写在里面。
小技巧:用 unzip 或 WinRAR 解压后,看一眼 CSV 文件里有没有 BOM 头。我遇到过几次因为 BOM 头导致 pandas 读取时列名多了一个 '\ufeff',排查了半天。
2.3 数据读取与初步探索
读取用 pandas 一行搞定。代码很简单:
import pandas as pd
train = pd.read_csv('data/raw/cs-training.csv')
test = pd.read_csv('data/raw/cs-test.csv')
读完之后先看形状和列名:
print(train.shape) # (150000, 12)
print(train.columns.tolist())
列名里有个坑——第一列是 Unnamed: 0,那是原始 CSV 里带的索引列。我建议你读的时候直接 index_col=0 把它吃掉,或者读完之后 drop 掉。不然后面 merge 的时候会多出一列莫名其妙的东西。
踩过的坑:我曾经在做训练集和测试集合并时忘记去掉索引列,结果行数翻倍还查不出原因。后来 debug 了两小时才发现是索引列造成的笛卡尔积。所以拿到数据第一件事——清理无意义的索引列。
再看一眼前 5 行和基本信息:
train.head()
train.info()
info() 会告诉你每列的非空计数和数据类型。这时候就能瞄出哪些列有缺失值。
2.4 数据集字段详解
我把字段含义整理成了表格,方便你对照。注意目标变量是 SeriousDlqin2yrs,1 表示违约,0 表示正常。
| 字段名 | 类型 | 含义 |
|---|---|---|
| Unnamed: 0 | int | 原始行号(建议删除) |
| SeriousDlqin2yrs | int | 目标变量:过去两年是否违约(0/1) |
| RevolvingUtilizationOfUnsecuredLines | float | 无担保额度使用率(总余额/总额度) |
| age | int | 借款人年龄 |
| NumberOfTime30-59DaysPastDueNotWorse | int | 过去2年逾期30-59天次数 |
| DebtRatio | float | 债务比率(月还款/月收入) |
| MonthlyIncome | float | 月收入 |
| NumberOfOpenCreditLinesAndLoans | int | 当前开放信贷/贷款数 |
| NumberOfTimes90DaysLate | int | 过去2年逾期90天以上次数 |
| NumberRealEstateLoansOrLines | int | 房产抵押贷款数 |
| NumberOfTime60-89DaysPastDueNotWorse | int | 过去2年逾期60-89天次数 |
| NumberOfDependents | int | 家属人数 |
字段名字真长…我早期做项目时每次都记不住,干脆在代码里用别名映射了一下。不过后来习惯了,其实读起来就那几类:逾期次数、额度使用率、收入债务比。你想想看,评分卡里最重要的几个因子都在里面了。
2.5 数据质量初探
马上就能发现问题。执行 train.isnull().sum() 看看:
SeriousDlqin2yrs 0
RevolvingUtilizationOfUnsecuredLines 0
age 0
NumberOfTime30-59DaysPastDueNotWorse 0
DebtRatio 0
MonthlyIncome 29731
NumberOfOpenCreditLinesAndLoans 0
NumberOfTimes90DaysLate 0
NumberRealEstateLoansOrLines 0
NumberOfTime60-89DaysPastDueNotWorse 0
NumberOfDependents 3924
嗯,MonthlyIncome 缺了将近 3 万条,占比约 20%;NumberOfDependents 缺了 3924 条。这俩坑后面必须处理。
另外看一眼 NumberOfTime30-59DaysPastDueNotWorse 的取值分布——我发现最大值居然是 98,明显是异常值。正常逾期次数怎么会有 98 次?这部分后续要单独揪出来处理。
第一印象总结:数据量够大,字段合理,缺失和异常主要集中在收入、逾期次数两个维度。后续清洗的思路已经比较清晰了。
这个流程图你看着可能觉得简单,但实际生产环境里,数据准备往往占整个项目 60% 以上的时间。为什么?因为数据不干净,后面的模型再花哨也是白搭。我最早做评分卡的时候,光数据准备就折腾了一周——下载、清洗、验证、再清洗…最后发现最简单的逻辑回归反而效果最好。嗯,数据质量才是王道。