ppd风控大赛数据集实战:从解压清洗到特征工程的完整建模流程
简介面向金融风控建模学习者的拍拍贷风控大赛原始数据集包含训练主表、日志信息表等CSV数据配套可视化图表与说明文档可用于信用风险评估、用户违约预测等实战练习。资源共176个文件以CSV数据文件为核心辅以JPG/PNG可视化图片、HTML/JS/CSS前端展示文件、XLSX表格、IPYNB分析笔记及文档整包约37.37MB结构清晰便于按需调用。已有1123人学习浏览比较适合希望接触真实信贷数据、从特征工程到模型评估完整走一遍风控流程的初学者和竞赛参与者。压缩包内不仅提供了多个结构化业务数据表还保留了网页分析记录与可视化输出可帮助理解数据探索思路缩短上手时间。用户可以据此练习逻辑回归、随机森林等常见风控模型并结合AUC-ROC等指标评估模型区分能力。1. ppd风控大赛数据集一个7z压缩包能解决什么问题打开这个 7z 压缩包你得到的不是能直接喂给模型的干净表格而是一堆带噪音的真实信贷业务数据。我在处理这类竞赛数据时最深的体感是真正卡人的地方从来不是模型调参而是“把业务表格变成训练样本”这个过程。ppd 数据集之所以值得折腾是因为它同时包含借款申请信息、用户历史行为文本描述和还款状态标签能完整串起一条“原始数据 → 特征 → 二分类模型”的风控建模链路。如果你正在学信贷风控、准备转岗风控算法或者只是想知道脱敏后的真实借贷数据长什么样花一个周末把它跑通比看十篇教程都管用。本文不涉及任何隐私信息只讲数据集本身的处理方法和工程习惯。2. 解压与拆包7z里的文件结构和字段清单先对齐2.1 先校验压缩包完整性再解压到独立目录我拿到这个 7z 包的第一件事不是急着双击解压而是先做完整性测试。很多竞赛数据包下载过程中容易断流解压报错时你甚至分不清是文件坏了还是密码错了。用命令行工具先测一遍# 测试压缩包是否完整7z 会逐个文件校验 CRC 7z t ppd拍拍贷风控大赛数据集.7z # 测试通过后解压到独立目录-o 后直接跟路径不要加空格 7z x ppd拍拍贷风控大赛数据集.7z -oppd_data第一条命令输出里如果出现Everything is Ok说明压缩包完整可以放心解压如果报某个文件 CRC Failed那就是下载损坏重新下载比强行修复省时间。第二条命令里的x表示保留完整目录结构解压-o指定输出目录。我一般会在项目根目录建一个raw/子目录专门放这种原始数据后面所有清洗脚本都从raw/读入绝不直接改动原始文件这样跑坏了随时能回到起点。不想装 7-Zip 的话Python 里有 py7zr 库也能解压但命令行更省事且解压速度通常更快。注意压缩包内文件名可能是中文Windows 下用 7-Zip 图形界面解压偶尔会出现文件名乱码命令行工具配合 UTF-8 编码一般能规避。2.2 把文件结构摸清楚表与表之间靠什么关联解压之后不要急着head看数据先列一下目录结构和文件大小建立整体认识ls -lh ppd_data/常见版本里这个包一般会拆成几张 CSV一张记录借款标的信息的表、一张记录借款用户信息的表以及附带的还款状态或标的进度字段。不同竞赛场次表名和字段名不完全一样但核心思路是一样的——先搞清楚“哪张表是主表哪张表是维表靠什么 key 关联”。我习惯把字段清单整理成一张映射表方便后续写特征时随时查阅。ppd 数据里值得关注的几类字段大致如下字段常见叫法类型在特征工程里的用途借款日期 / 申请时间时间构造时间特征、切分训练集借款金额数值金额类特征、组合特征借款利率数值风险定价因子区间划分借款期限数值与金额组合成月还款额历史成功借款次数数值用户活跃度历史逾期次数数值用户信用历史核心变量历史正常还款次数数值与逾期次数组合成履约率借款描述文本文本长度、关键词特征还款状态离散目标 label 的唯一来源注意一个容易翻车的细节表内粒度。ppd 数据的借款表通常是一个用户有多笔借款记录每笔一行用户维表则可能是每个用户一行。如果你直接把两张表merge之后再 groupby 算用户特征会出现同一用户的维表字段被复制到多行里导致统计翻倍。正确做法是先确定你要建模的粒度——是“每笔借款”还是“每个用户”——再决定共享特征的计算方式。绝大多数竞赛场景默认按借款粒度做二分类因为同一用户的不同借款会有不同结果样本量也更大。3. 从数据集到训练样本定标签、设粒度、对齐时间3.1 读 CSV 前先想清楚编码、类型和缺失值ppd 这份数据里中文文本多CSV 读进来最常见的翻车点是编码。我见过不少同学用默认编码读结果借款描述列全是乱码还以为是数据脱敏把文本打码了。我一般这样设定读取参数import pandas as pd # 先用 utf-8 尝试读报 UnicodeDecodeError 就换 gbk 或 utf-8-sig df pd.read_csv( ppd_data/标的表.csv, encodingutf-8-sig, dtype{借款描述: string}, # 强制字符串类型避免被解析成其他类型 parse_dates[借款日期], # 日期列直接转成 datetime方便后续切片 )utf-8-sig能自动处理带 BOM 的文件头比单纯utf-8更稳。dtype参数里指定文本列为string是关键一步如果不指定Pandas 遇到一列中绝大多数是空值时会把整列类型推断成float后面做字符串操作全部报错。parse_dates把日期列提前转好比你事后pd.to_datetime()逐列处理要快得多。读进来以后先打印三个东西df.shape、df.dtypes、df.isnull().sum()。这里能看到最真实的样本量和缺失率。我见过有人忽略 shape 直接开始写特征脚本结果把训练集和测试集拼接起来一起做了标准化导致信息泄漏这就是没先建立数据全貌的代价。3.2 还款状态列怎么翻译成 0/1 标签ppd 数据集里最重要的列是还款状态。它通常不是干净的 0/1而是多取值状态比如“还款中”“已还清”“逾期”“严重逾期”等等。这里需要做一道判断题哪些状态算正样本哪些算负样本。# 先看分布再决定切分口径 print(df[还款状态].value_counts(dropnaFalse)) # 常规做法把非正常结清的状态统一标记为坏样本1正常结清为 0 # 注意不同比赛口径可能不同以你下载版本的说明为准 df[target] (df[还款状态] ! 已还清).astype(int)value_counts(dropnaFalse)里dropnaFalse的细节不要省因为数据里可能存在空状态你不看它就永远不知道缺失状态到底算好还是算坏。切分口径上我倾向于只把明确“已还清”当作 0其余一律归为 1这样坏样本的定义更保守模型学到的规律也更接近风控的真实含义。如果你发现某类状态占比奇高比如一半样本都是“还款中”说明这批数据的观测窗口还没走完此时最好直接丢掉“还款中”的样本而不是硬归到哪一边否则标签噪声会严重拉低模型上限。3.3 备份一份纯数值干净的宽表再做特征特征工程之前我习惯先做一步数据清洗并另存宽表后续所有特征都在这张表上追加。这样做的好处是万一某个特征写坏了从宽表重新跑就行不用重新读原始 CSV。# 只保留必要列减少内存占用 base df[[借款id, 用户id, 借款日期, 借款金额, 借款利率, 借款期限, target]].copy() # 排序并重置索引方便时间窗口切片 base base.sort_values(借款日期).reset_index(dropTrue) # 保存中间结果后续特征脚本从这里读 base.to_pickle(ppd_data/base.pkl)用to_pickle保存中间结果是个被低估的好习惯。CSV 每次读取都重新解析一遍类型和日期而 pickle 直接保存 Pandas 内部结构读回来速度快一个量级且类型不会漂移。数据量不大时随便用如果后续数据量涨到几百万行同样套路换成parquet格式更稳。4. 基于ppd原始字段做特征工程金额、历史行为与借款描述4.1 金额、利率和期限的组合特征先于单字段特征做特征的第一条原则我通常这样执行先把业务上明显相关的字段组合起来再考虑单字段。借款金额和借款期限单独看信息量一般但组合成“月还款额”后就能和用户收入水平形成对照模型更容易抓到“月供过高导致违约”的模式。这个动作有几个常见写法# 在 base 基础上追加组合特征 base[月还款额] base[借款金额] / base[借款期限] base[期限利率积] base[借款期限] * base[借款利率] base[金额分档] pd.qcut(base[借款金额], q5, labelsFalse, duplicatesdrop)pd.qcut按分位数把金额切成五档比直接扔连续值更稳因为金额长尾严重连续值进树模型容易被极值拉扯。duplicatesdrop是防止分位数边界重复时报警。注意组合特征不要无限做两个字段做成加减乘除四则运算就够了再往上拼不仅意义不大还会让树模型的特征重要性分散增加排查成本。做完这一步后跑一个简单的corr看一下月还款额和借款金额的相关系数通常高达 0.9 以上这是预期内的——特征之间线性相关对树模型无害但对后续做逻辑回归或线性模型的人是个坑。如果你计划对比线性模型就得考虑先做去相关或正则化。4.2 用户历史行为先想清楚是求和还是取最近值ppd 数据里关于用户历史的字段不少常见的有历史成功借款次数、历史逾期次数、历史正常还款次数。头次接触的人容易犯一个错直接用这些字段的原始值进模型。但同一用户有多笔借款记录时这些字段在每行里是重复的本质上没有行间区分度。我一般这样处理# 先按用户聚合算用户的整体信用画像 user_feat df.groupby(用户id).agg( 历史借款笔数(借款id, count), 历史逾期次数最大(历史逾期次数, max), 历史正常还款次数最大(历史正常还款次数, max), 平均借款金额(借款金额, mean), ).reset_index() # 再合并回借款表注意是左连接保证每笔借款都拿到用户画像 base base.merge(user_feat, on用户id, howleft)这里的关键区别在于max还是sum“历史逾期次数”在大多数脱敏数据里已经是截至当前借款前的历史累计值直接sum会把多笔借款的累计值重复相加造成严重偏差。拿不准字段口径时可以对同一用户做一次df.groupby(用户id)[历史逾期次数].nunique()检查——正常累计值在同一用户的不同借款记录里应该保持一致如果每行都不一样说明字段本身就是按借款周期统计的那时才可以考虑sum。这个检查只要一分钟但能帮你避开一个很隐蔽的错误特征。4.3 借款描述文本长度、关键词和空值标记ppd 数据里有一个文本列借款描述或借款用途。文本类特征在树模型里不好直接利用但可以提取三个层面的信息。第一是长度借款人写得多不多某种程度上反映申请的认真程度。第二是关键词比如“周转”“医疗”“装修”等用途词。第三是是否有内容——如果大量用户此列为空空本身也是一个信号。# 文本特征三件套 base[描述长度] df[借款描述].str.len() base[描述是否为空] df[借款描述].isna().astype(int) base[描述含周转] df[借款描述].fillna().str.contains(周转|资金周转).astype(int) # 长度列常存在极端值做一次截断更稳 base[描述长度_截断] base[描述长度].clip(upper200).clip(upper200)把长度限制在 200 以内防止个别几千字的长文把特征尺度拉爆。关键词那部分我一般只选两到三个业务上最明确的词不要搞一个几十词的词典——词表越大过拟合风险越高而且换一批数据基本不可复用。文本特征在 ppd 这种数据上的收益通常不大但聊胜于无它能帮你看见“用户主动描述”这个行为本身是否与违约相关。4.4 时间对齐把所有特征锁在“借款申请日之前”风控建模里最严肃的一条底线是特征时效性——任何特征都不能包含样本发生后才能知道的信息。ppd 数据里最容易踩这个线的地方是用户历史类字段因为脱敏时经常把整张表导出某些“历史逾期次数”可能包含了借款之后新产生的逾期记录。验证方法很简单# 构造一个带截止日期的特征版本只用申请日之前的数据 cutoff pd.Timestamp(2019-06-30) valid_df base[base[借款日期] cutoff].copy()这个cutoff是模拟你在某个时间点做决策把这之前的数据当训练集之后的数据当验证集。如果某列特征在cutoff前后分布出现突变多半就是那个列里混进了未来信息需要回到原始 CSV 重新确认字段口径。时间对齐这事没有捷径只能靠这种“按时间切分后对比特征分布”的办法反复排查。宁可少几个特征也不能留一个穿越特征否则模型上线必翻车。5. 做ppd风控建模必踩的坑缺失值、统计泄漏与时间穿越5.1 认证类字段缺失率 90%填充还是丢弃现象某列认证信息缺失率超过 90%直接fillna(未认证)之后发现模型把这个特征当成最强变量验证 AUC 高得异常。原因这类字段只在用户主动上传或授权时才存在缺失本身不代表“未认证”而可能是脱敏时只保留了部分记录。填充成“未认证”等于自己制造了一个与标签高度相关的假变量纯属统计泄漏。解决先看缺失率缺失率超过 95% 的列直接丢弃缺失率在 50% 到 95% 之间的列把缺失本身变成一个二值标志位值域再放进模型。不要用均值填充也不要用中位数填充信贷数据的缺失模式本身就是有业务含义的强行填充只会掩盖信息。5.2 训练 AUC 0.99验证 AUC 0.70现象随机切分训练集时模型表现极好一换到按时间划分的验证集就崩。原因这是典型的字段泄漏。ppd 数据里有些列跟目标列同源例如“是否逾期”“当前状态”这类字段本身就是还款状态的变体被当成特征喂进了模型。另外如果同一用户的某笔借款结果已经确定而他的另一笔借款记录里带上了这次结果的历史汇总也会造成泄漏。解决建特征前把所有列名列出来凡是名字里带“状态”“结果”“是否”的列先全部移出特征池等模型基线跑通之后再决定要不要加回。统一规则是特征列必须是在借款申请时点已经确定的信息任何涉及还款结果的列都是标签不是特征。5.3 随机 K 折切分导致 AUC 虚高现象同一套特征用train_test_split(random_state42)得到的 AUC 是 0.85换成时间序列切分后变成 0.73。原因ppd 数据里同一个用户有多笔借款随机切分时同一用户的借款会同时出现在训练集和验证集模型直接记住了用户 ID 或用户维度的统计特征验证分数自然虚高。解决用TimeSeriesSplit或GroupKFold做验证。GroupKFold按用户 ID 分组保证同一个用户的全部借款只落在训练集或验证集的一侧这样测出来的分数才是模型真正面对新用户时的表现。如果两组分数差异大于 0.08说明特征里用户级信息过重需要重新审视。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5) # 每一折都用更早的时间段训练、更晚的时间段验证 # 比随机 K 折更贴近真实风控场景 for train_idx, val_idx in tscv.split(base): train base.iloc[train_idx] val base.iloc[val_idx] # 这里再单独做 GroupKFold 按用户去重校验5.4 借款描述列读进来全变成 NaN现象head()看前几行文本正常一跑str.len()就报错说对象不是字符串。原因Pandas 在读取时如果发现某文本列包含空值会把整列推断为float类型后续字符串操作全部失效还有一部分原因是文件里包含中文引号或特殊转义字符导致解析错位。解决读取时强制指定dtype{借款描述: string}并且给str操作统一加.fillna()保证类型正确再操作。要是读进来的文本自带换行符先.str.replace(\n, )清洗一遍再做长度和关键词提取。这个坑不深但很烦人提前指定 dtype 能省下半小时。6. 用SHAP值回看模型验证特征依赖是否符合业务逻辑6.1 树模型训练完之后用 SHAP 替代 feature_importance特征工程跑完模型训练是后半段的事。我用 LightGBM 做二分类时习惯直接看 SHAP 值而不是默认的feature_importance因为默认重要性只看“用过多少次”而 SHAP 能告诉你“特征多大程度上把预测推向 0 或 1”。这一步是验证模型是否学歪的关键。import lightgbm as lgb import shap X base[feature_cols] y base[target] train_data lgb.Dataset(X_train, y_train) val_data lgb.Dataset(X_val, y_val, referencetrain_data) params { objective: binary, learning_rate: 0.05, max_depth: -1, num_leaves: 63, min_child_samples: 100, feature_fraction: 0.8, bagging_fraction: 0.8, verbose: -1, } model lgb.train( params, train_data, num_boost_round500, valid_setsval_data, callbacks[lgb.early_stopping(50)], ) explainer shap.TreeExplainer(model) shap_values explainer.shap_values(X_val) shap.summary_plot(shap_values, X_val)early_stopping(50)表示连续 50 轮验证集分数不提升就停止能省下大量无效迭代。min_child_samples100是风控数据里常用的防过拟合参数保证叶子节点至少有 100 个样本——信贷数据正负样本不平衡叶子节点太小学到的全是噪声。summary_plot画出来的图上纵轴按特征重要性排序横轴看 SHAP 值方向红色代表特征取值高蓝色代表取值低。拿这张图去和业务常识对一遍借款利率高、历史逾期次数多的用户预测坏概率是不是相应更高。如果是反的优先怀疑标签切错或特征中混入了未来信息。6.2 把 SHAP 结论还原成一句话再决定是否信任模型SHAP 图确认特征方向正确之后我习惯挑两三个高重要性特征做一次分组统计来交叉验证。比如按历史逾期次数分组看每组的坏样本率是否单调递增按借款利率分档看高利率档位违约率是否更高。这种分组验证比任何指标都直观也是给业务方展示模型逻辑时的最好素材。实际动手做这个数据集时我发现借款金额和利率方向很稳定但借款描述里的关键词特征在不同版本数据上方向会变——某些词在训练集里是坏的信号换一批样本变成好信号。所以文本关键词这列我在最终模型里要么舍掉要么只保留长度和空值标志不让它参与关键决策。做完数据集的完整流程我对竞赛数据的处理习惯有一些变化每张表先确认粒度每个潜在标签先看分布每条时间特征先判断时点。这三个习惯救过我很多次也让模型的验证分数经得起推敲。希望这次关于 ppd 风控数据集从解压、定标签、特征工程到验证的完整拆解帮你在面对真实信贷数据时少走几步弯路。本文还有配套的精品资源点击获取