mcpField
T
tabular-eda

tabular-eda

github.com/brojonat数据与数据库135 次安装1 周前更新
代码仓库

关于 tabular-eda

tabular-eda 是一项在建模前检查表格数据集的技能。它引导使用者排查数据质量问题,并输出包含特征名称和建议操作的发现报告,同时提供图表与 JSON 报告。

主要功能

  1. 01推断目标类型与任务
  2. 02分析缺失值和数据分布
  3. 03检测目标泄漏与冗余特征
  4. 04查找高基数及近常量列
  5. 05生成图表和 findings.json

适用场景

  1. 01检查新收到的数据集
  2. 02排查模型结果异常
  3. 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 秒内回答“这些数据里有什么?”:

  1. 缺失数据条形图——按缺失百分比降序排列
  2. 数值分布网格图——直方图并标注偏度
  3. 类别特征基数条形图——唯一值超过 50 个的类别用红色条形表示
  4. 相关性热力图——特征 × 目标的 Pearson 相关性,并在目标列旁标注实际数值
  5. 互信息与 Pearson 并列条形图——呈现 Pearson 遗漏的非线性信号
  6. 离群值箱线图——按数值列绘制,并标注基于 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(没有明显目标)→ 无监督技能

常见陷阱

  1. 完全跳过 EDA。“我直接把它丢给 XGBoost 就行。”这正是目标泄漏和“测试准确率达 99%,但上线后就出问题”的成因。
  2. **只看 Pearson 相关性。**这会遗漏正弦、二次关系和类别关系。务必结合互信息一起看。
  3. **未与数据负责人确认就删掉“泄漏”特征。**有时该特征是合理的(例如上游模型的预测结果)。删除前务必确认。
  4. **对高基数类别特征进行 OneHotEncoding。**这会导致特征数量激增、噪声淹没模型,并拖慢训练。应使用目标编码、频率编码,或者直接删掉该列。
  5. **不检查重复项。**如果数据集中有 50% 的重复行,且重复项同时出现在训练集和测试集中,测试指标就会虚高。
  6. **不加思考地填补缺失值。**对于 MCAR,可以用中位数填补;但对于 MAR/MNAR,可能需要对缺失本身进行建模。务必标记缺失模式,不要悄悄填补。
  7. **把 EDA 报告当作临时产物。**将发现 JSON 和图表记录到 MLflow(或你使用的其他实验跟踪工具)中。模型在六个月后失效时,你会希望能查看数据首次分析时的 EDA 报告。

示例演练

请参阅 demo.py(marimo 笔记本)。它会生成一个经过刻意设计、问题繁多的合成二分类数据集,其中植入了 七个问题(目标泄漏、高基数类别特征、近乎恒定的特征、30% 的数据缺失、对数正态偏度、2% 的离群值、冗余特征对),并逐一演示如何检测。笔记本最后会生成一个发现汇总表,展示 EDA 流程捕获了哪些问题;该表就是回答“接下来该训练什么模型?”的依据。

EDA 之后:下一步怎么做

根据发现决定:

  • 删除:泄漏特征、近乎恒定的特征,以及每对冗余特征中的一个
  • 编码:使用目标编码、频率编码或哈希编码处理高基数类别特征
  • 填补:填补缺失数据(数值型用中位数,类别型用“missing”哨兵值)
  • 转换:处理偏度较大的特征(对数、Box-Cox)和离群值(缩尾或使用稳健缩放器)
  • 然后:调用相应的问题类型技能(二分类、回归、多分类等)

评论

支持 Markdown