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

Pandas下采样时如何保留各列按target分组的频率分布?

下采样保留target分组下各列频率分布的实现方法

需求说明

我有一个示例pandas dataframe df,数据结构如下:

{'column_a': {0: 'b',   1: 'b',  2: 'a',  3: 'b',  4: 'd',  5: 'a',  6: 'b',  7: 'b',  8: 'c',  9: 'a',  10: 'a',  11: 'a',  12: 'a',  13: 'c',  14: 'c',  15: 'c',  16: 'b',  17: 'a',  18: 'a',  19: 'b',  20: 'd',  21: 'c',  22: 'a',  23: 'b',  24: 'c',  25: 'c',  26: 'c',  27: 'e',  28: 'e',  29: 'e',  30: 'e',  31: 'c',  32: 'e',  33: 'e',  34: 'd',  35: 'e',  36: 'd',  37: 'e',  38: 'd',  39: 'b',  40: 'd',  41: 'c',  42: 'b',  43: 'd',  44: 'c',  45: 'e',  46: 'd',  47: 'c',  48: 'e',  49: 'b',  50: 'c'}, 'column_b': {0: 'c',  1: 'b',  2: 'b',  3: 'd',  4: 'b',  5: 'a',  6: 'd',  7: 'c',  8: 'c',  9: 'd',  10: 'a',  11: 'a',  12: 'b',  13: 'a',  14: 'c',  15: 'd',  16: 'd',  17: 'c',  18: 'b',  19: 'd',  20: 'a',  21: 'a',  22: 'd',  23: 'b',  24: 'a',  25: 'c',  26: 'e',  27: 'd',  28: 'b',  29: 'c',  30: 'd',  31: 'b',  32: 'e',  33: 'b',  34: 'b',  35: 'c',  36: 'b',  37: 'b',  38: 'd',  39: 'c',  40: 'b',  41: 'a',  42: 'b',  43: 'e',  44: 'e',  45: 'c',  46: 'e',  47: 'c',  48: 'b',  49: 'b',  50: 'c'}, 'column_c': {0: 'b',  1: 'd',  2: 'b',  3: 'b',  4: 'd',  5: 'c',  6: 'b',  7: 'a',  8: 'a',  9: 'a',  10: 'a',  11: 'b',  12: 'd',  13: 'c',  14: 'b',  15: 'a',  16: 'a',  17: 'a',  18: 'b',  19: 'c',  20: 'a',  21: 'a',  22: 'b',  23: 'd',  24: 'd',  25: 'c',  26: 'd',  27: 'c',  28: 'c',  29: 'e',  30: 'd',  31: 'c',  32: 'd',  33: 'c',  34: 'b',  35: 'b',  36: 'd',  37: 'd',  38: 'd',  39: 'b',  40: 'c',  41: 'e',  42: 'e',  43: 'b',  44: 'b',  45: 'd',  46: 'd',  47: 'c',  48: 'e',  49: 'd',  50: 'b'}, 'column_d': {0: 'b',  1: 'c',  2: 'd',  3: 'd',  4: 'b',  5: 'b',  6: 'd',  7: 'd',  8: 'd',  9: 'b',  10: 'd',  11: 'c',  12: 'b',  13: 'a',  14: 'c',  15: 'c',  16: 'd',  17: 'c',  18: 'd',  19: 'a',  20: 'd',  21: 'b',  22: 'd',  23: 'b',  24: 'd',  25: 'e',  26: 'c',  27: 'c',  28: 'c',  29: 'd',  30: 'c',  31: 'e',  32: 'd',  33: 'd',  34: 'd',  35: 'b',  36: 'c',  37: 'e',  38: 'b',  39: 'e',  40: 'b',  41: 'c',  42: 'b',  43: 'e',  44: 'b',  45: 'c',  46: 'd',  47: 'c',  48: 'c',  49: 'b',  50: 'd'}, 'target': {0: 1,  1: 1,  2: 1,  3: 1,  4: 1,  5: 1,  6: 1,  7: 1,  8: 1,  9: 1,  10: 1,  11: 1,  12: 1,  13: 1,  14: 1,  15: 1,  16: 1,  17: 1,  18: 1,  19: 1,  20: 1,  21: 1,  22: 1,  23: 1,  24: 1,  25: 0,  26: 0,  27: 0,  28: 0,  29: 0,  30: 0,  31: 0,  32: 0,  33: 0,  34: 0,  35: 0,  36: 0,  37: 0,  38: 0,  39: 0,  40: 0,  41: 0,  42: 0,  43: 0,  44: 0,  45: 0,  46: 0,  47: 0,  48: 0,  49: 0,  50: 0}}

需要对该DataFrame按任意指定行数或比例下采样,同时尽可能保留每个target类别下各列不同取值的频率分布。
直接使用.sample()方法执行下采样,如smaller_df = df.sample(n=100)或smaller_df = df.sample(frac=0.1),很可能破坏每个类别下各列的取值分布。
可以通过如下代码查看当前的频率密度:

for col in df.columns:
    print(df.groupby(['target'])[col].value_counts(normalize=True))

输出示例如下:

target        column_a
0       e           0.384615
        c           0.269231
        d           0.230769
        b           0.115385
1       a           0.360000
        b           0.320000
        c           0.240000
        d           0.080000

现有公开方案仅能解决保留单一分布的下采样问题,无法满足多列分布同时保留的需求,真实数据集规模为(8370994, 731)。

实现方案

采用分层分组抽样逻辑,先按target列拆分不同类别子集,每个子集内独立按比例/指定行数随机抽样,既能保留target的原始分布,也能保证每个target分组内所有列的频率分布和原数据完全一致。

按比例下采样代码

import pandas as pd

# 自定义下采样比例,例如下采样到原数据的10%
sample_frac = 0.1
# random_state固定可保证结果可复现
sampled_df = df.groupby('target', group_keys=False).apply(
    lambda x: x.sample(frac=sample_frac, random_state=42)
)

按指定总行数下采样代码

import pandas as pd

# 自定义总采样行数,例如采样10000行
total_sample_n = 10000
# 计算原数据各target类别的占比
target_ratio = df['target'].value_counts(normalize=True)
# 按占比分配每个类别的采样行数
sample_n_per_target = (target_ratio * total_sample_n).round().astype(int)

# 修正行数误差,避免分配后总条数和预期不一致
diff = total_sample_n - sample_n_per_target.sum()
if diff != 0:
    sample_n_per_target.iloc[0] += diff

# 分组执行抽样
sampled_df = df.groupby('target', group_keys=False).apply(
    lambda x: x.sample(n=sample_n_per_target[x.name], random_state=42)
)

方案说明

  • 该方法逻辑简单高效,针对千万级行、数百列的大规模数据集也可以正常运行,无额外内存开销
  • 每个target分组内的随机抽样天然保留了组内所有列的单变量分布、列间联合分布,不会出现分布偏移
  • 可通过以下代码验证采样后的分布是否符合预期:
for col in sampled_df.columns:
    print(sampled_df.groupby(['target'])[col].value_counts(normalize=True))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 10:06:03