第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 次?这部分后续要单独揪出来处理。

第一印象总结:数据量够大,字段合理,缺失和异常主要集中在收入、逾期次数两个维度。后续清洗的思路已经比较清晰了。

数据准备流程概览 1. 从 Kaggle 下载 2. 解压 + read_csv 3. shape / info / head 4. 发现缺失 & 异常值 5. 清洗方向:填充/截断/变换 ⚠ 收入缺失率 20%,家属缺失 2.6%; 逾期次数最大值 98(明显异常),需单独检测。

这个流程图你看着可能觉得简单,但实际生产环境里,数据准备往往占整个项目 60% 以上的时间。为什么?因为数据不干净,后面的模型再花哨也是白搭。我最早做评分卡的时候,光数据准备就折腾了一周——下载、清洗、验证、再清洗…最后发现最简单的逻辑回归反而效果最好。嗯,数据质量才是王道。