关于 tabular-eda
tabular-eda 是一项在建模前检查表格数据集的技能。它引导使用者排查数据质量问题,并输出包含特征名称和建议操作的发现报告,同时提供图表与 JSON 报告。
主要功能
- 01推断目标类型与任务
- 02分析缺失值和数据分布
- 03检测目标泄漏与冗余特征
- 04查找高基数及近常量列
- 05生成图表和 findings.json
适用场景
- 01检查新收到的数据集
- 02排查模型结果异常
- 03建模前验证数据质量
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ brojonat/ llmsrules --skill tabular-eda安装后在 Claude Code 中输入/tabular-eda确认已加载。
附带文件scripts/demo.py
详细介绍
表格数据探索性分析——正确的方法
每当你拿到一个新的表格数据集,先停下来。不要直接开始写 XGBClassifier()。花 10 分钟做探索性数据分析,就能发现那些可能毁掉下游模型的问题——目标泄漏、高基数爆炸、MAR 缺失数据,以及 Pearson 相关性认为毫无用处的非线性特征。这就是这套工作流的意义。
何时使用此技能
- 你刚收到一个新数据集,还不知道里面有什么
- 你准备训练模型,想先验证数据
- 模型的表现好得可疑(或差得可疑),你怀疑存在数据质量问题
- 用户问“我该如何处理这个数据集?”
何时不使用此技能
- 你已经非常了解这个数据集,并且此前做过数据分析
- 数据集是图像/文本/音频/时间序列——这些数据有不同的规则
- 用户只想快速训练一个模型,并且愿意承担风险
工作流
1. Load → shape, dtypes, memory
2. Identify the target → infer problem type (binary / multiclass / regression)
3. Missing data → per-column %, overall %, patterns
4. Numeric distributions → skew, outliers, scale mismatches
5. Categorical cardinality → flag high-cardinality (OHE explosion risk)
6. Near-constant features → flag and consider dropping
7. Redundant pairs → flag features with > 0.95 mutual correlation
8. **Target leakage detection** → flag features with > 0.95 |Pearson| to target
9. **Mutual information vs Pearson** → catch non-linear features Pearson misses
10. Optional: PCA / UMAP for low-dim visualization
输出是一份发现报告:列出可疑之处,并为每一项注明特征名称、触发警报的指标以及建议采取的措施。不要只打印图表。 列出具体问题及其名称,才能据此采取行动。
这套方法有别于教程的五个方面
1. 目标泄漏检测——最有价值的一项 EDA 检查
“泄漏”特征是指包含了预测时实际上无法获得的目标信息的特征。典型例子:
- 用
account_balance_after_payment预测made_payment - 用累计的
total_charges预测churned - 用
claim_paid_amount预测claim_was_filed
这些特征是在预测时点之后计算的。用它们训练,你会得到 99% 的测试准确率,但模型在生产环境中会彻底失效。典型迹象是与目标的相关性高得可疑——任何 > 0.95 的特征都应怀疑存在泄漏,任何 > 0.99 的特征几乎肯定存在泄漏。
def find_leakage_candidates(df, target_col, numeric_cols, threshold=0.95):
out = []
for col in numeric_cols:
if col == target_col:
continue
corr = float(df[[col, target_col]].dropna().corr().iloc[0, 1])
if abs(corr) > threshold:
out.append({"feature": col, "pearson": round(corr, 4)})
return out
发现疑似泄漏特征时,务必先向数据所有者确认,再将其删除。有时某个特征确实与目标几乎完全相关(例如上游模型的预测结果)。但默认应假设“这是泄漏”。
2. 互信息与 Pearson 对比——发现非线性信号
Pearson 相关性只能捕捉线性关系。若某个特征通过 sin(x) 或 (x - 0.5)² 影响目标,它的 Pearson 相关性可能 ≈ 0,而仅靠 Pearson 会将其判定为无用。互信息则能捕捉两者。
from sklearn.feature_selection import mutual_info_classif, mutual_info_regression
# For classification
mi_scores = mutual_info_classif(X, y, random_state=0)
# For regression
mi_scores = mutual_info_regression(X, y, random_state=0)
将 |Pearson| 和 MI 并排绘制成柱状图。MI 高但 |Pearson| 低的特征,说明有非线性信号隐藏在线性 EDA 中。线性模型会看不到这些信号,但 XGBoost 会从中获益。
回归工具包通过 Friedman1 的 sin(π·x₀·x₁) 项传达的也是这一道理:线性相关性为零,互信息很高,对目标的贡献也很大。
3. 高基数类别特征检测
像 user_id 这样的列有数千个唯一值,会让 OneHotEncoder 扩展出数千个稀疏列。应标记唯一值超过 50 个的类别特征:
def find_high_cardinality(df, cat_cols, threshold=50):
return [
{"feature": c, "n_unique": int(df[c].nunique())}
for c in cat_cols if df[c].nunique() > threshold
]
对高基数类别特征的建议处理方式:
- 目标编码(按类别计算目标的平滑均值)——效果不错,但如果交叉验证时不够谨慎,就会发生泄漏
- 频率编码——将每个类别替换为其出现频率
- 哈希编码——使用固定大小的哈希桶
- 直接删除——
user_id通常不是有用的特征
4. 近乎常量特征检测
如果某一列中的一个值覆盖了 > 98% 的行,这一列基本没有信号。保留它不一定错(有信号总比没有好),但它通常表明存在数据采集问题,值得标记:
def find_near_constant(df, threshold=0.98):
return [
{"feature": c, "top_value_freq": float(df[c].value_counts(normalize=True).iloc[0])}
for c in df.columns
if df[c].value_counts(normalize=True).iloc[0] > threshold
]
5. 冗余特征检测
相互相关性 > 0.95 的特征携带相同信息。 从每对特征中删去一个,以减少多重共线性(它对线性模型的影响大于对树模型的影响,但仍会浪费计算资源):
def find_redundant_pairs(df, numeric_cols, threshold=0.95):
corr = df[numeric_cols].corr().abs()
out = []
for i, c1 in enumerate(numeric_cols):
for c2 in numeric_cols[i + 1:]:
if float(corr.loc[c1, c2]) > threshold:
out.append({"pair": [c1, c2], "pearson": float(corr.loc[c1, c2])})
return out
可视化检查(始终包含在输出中)
这六种图表结合起来,可以在 30 秒内回答“这些数据里有什么?”:
- 缺失数据条形图——按缺失百分比降序排列
- 数值分布网格图——直方图并标注偏度
- 类别特征基数条形图——唯一值超过 50 个的类别用红色条形表示
- 相关性热力图——特征 × 目标的 Pearson 相关性,并在目标列旁标注实际数值
- 互信息与 Pearson 并列条形图——呈现 Pearson 遗漏的非线性信号
- 离群值箱线图——按数值列绘制,并标注基于 IQR 的离群值数量
在图表旁输出一个 findings.json 文件。每条发现都包含特征名称、触发标记的指标以及建议操作。 后续操作以该列表为准;图表则作为佐证。
目标类型推断
建模前,先通过启发式方法推断目标类型:
def infer_target_type(y):
if y.dtype.kind in "biu": # bool / int
n_unique = y.nunique()
if n_unique == 2:
return "binary"
if n_unique <= 20:
return "multiclass"
return "regression"
if y.dtype.kind == "f":
return "regression"
return "categorical"
这会告诉你接下来要调用哪种下游技能:
binary→ 二分类技能multiclass→ 多分类技能regression→ 回归技能categorical(没有明显目标)→ 无监督技能
常见陷阱
- 完全跳过 EDA。“我直接把它丢给 XGBoost 就行。”这正是目标泄漏和“测试准确率达 99%,但上线后就出问题”的成因。
- **只看 Pearson 相关性。**这会遗漏正弦、二次关系和类别关系。务必结合互信息一起看。
- **未与数据负责人确认就删掉“泄漏”特征。**有时该特征是合理的(例如上游模型的预测结果)。删除前务必确认。
- **对高基数类别特征进行 OneHotEncoding。**这会导致特征数量激增、噪声淹没模型,并拖慢训练。应使用目标编码、频率编码,或者直接删掉该列。
- **不检查重复项。**如果数据集中有 50% 的重复行,且重复项同时出现在训练集和测试集中,测试指标就会虚高。
- **不加思考地填补缺失值。**对于 MCAR,可以用中位数填补;但对于 MAR/MNAR,可能需要对缺失本身进行建模。务必标记缺失模式,不要悄悄填补。
- **把 EDA 报告当作临时产物。**将发现 JSON 和图表记录到 MLflow(或你使用的其他实验跟踪工具)中。模型在六个月后失效时,你会希望能查看数据首次分析时的 EDA 报告。
示例演练
请参阅 demo.py(marimo 笔记本)。它会生成一个经过刻意设计、问题繁多的合成二分类数据集,其中植入了 七个问题(目标泄漏、高基数类别特征、近乎恒定的特征、30% 的数据缺失、对数正态偏度、2% 的离群值、冗余特征对),并逐一演示如何检测。笔记本最后会生成一个发现汇总表,展示 EDA 流程捕获了哪些问题;该表就是回答“接下来该训练什么模型?”的依据。
EDA 之后:下一步怎么做
根据发现决定:
- 删除:泄漏特征、近乎恒定的特征,以及每对冗余特征中的一个
- 编码:使用目标编码、频率编码或哈希编码处理高基数类别特征
- 填补:填补缺失数据(数值型用中位数,类别型用“missing”哨兵值)
- 转换:处理偏度较大的特征(对数、Box-Cox)和离群值(缩尾或使用稳健缩放器)
- 然后:调用相应的问题类型技能(二分类、回归、多分类等)