You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dask dataframe上实现Leave one out留一编码

Dask DataFrame 实现留一(Leave-One-Out)目标编码

留一编码的核心逻辑不需要逐行遍历排除样本,完全可以通过全局聚合+回表扣减当前行贡献的方式实现,天然适配Dask的分块并行计算模型,哪怕分类类别超过1000、数据量很大也能高效运行,不会出现内存瓶颈。

实现步骤

  • 先计算全量目标列y的全局均值,用于填充仅出现1次的分类(避免计算时除零错误)
  • 按待编码的分类列分组,统计每个分类下的y总和、样本总计数:这一步Dask会自动分块执行聚合,且聚合结果的行数等于分类类别数,哪怕上万个类别体量也非常小,可以直接拉到本地内存
  • 将聚合统计结果合并回原Dask DataFrame
  • 计算留一编码值:(分类总y和 - 当前行y值) / (分类总样本数 - 1),如果分类仅出现1次,直接用全局y均值填充即可

可直接运行的代码

import dask.dataframe as dd
import pandas as pd
import numpy as np

# 示例数据
df = pd.DataFrame({
    "A": [1, 2, 1, 2, 3, 1, 2, 3, 5], 
    "B": ["a", "b", "c", "c", "a", "b", "b", "a", "c"], 
    "y":[0, 10, 2, 1, 4, 1, 6, 12, 11]
})
X = dd.from_pandas(df, npartitions=2)

# 全局y均值,处理单样本分类的边界情况
global_y_mean = X.y.mean().compute()

# 按分类列B聚合统计
group_stats = X.groupby("B").agg(
    group_y_sum=("y", "sum"),
    group_count=("y", "count")
).compute()

# 合并统计值回原表
X_encoded = X.merge(group_stats, left_on="B", right_index=True, how="left")

# 计算留一编码
X_encoded["B_loo_encoded"] = np.where(
    X_encoded["group_count"] > 1,
    (X_encoded["group_y_sum"] - X_encoded["y"]) / (X_encoded["group_count"] - 1),
    global_y_mean
)

# 删除临时统计列
X_encoded = X_encoded.drop(columns=["group_y_sum", "group_count"])

# 触发计算查看结果
print(X_encoded.compute())

注意事项

  • 该实现完全避免目标泄露:编码值严格排除了当前行的y值,符合留一编码的定义
  • 不存在分区偏差:聚合是基于全量数据计算的,不会因为Dask分块出现统计值不准的问题
  • 训练/测试集拆分场景下,必须只用训练集数据计算group_stats和global_y_mean,再映射到验证/测试集,绝对不能把测试集的y信息纳入统计,否则会造成数据泄露
  • 如果有多个分类列需要编码,对每个分类列重复执行「聚合-合并-计算编码」的流程即可,单分类的聚合结果体量极小,不会带来额外性能压力

内容的提问来源于stack exchange,提问作者Shawn Brar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 07:51:28