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

如何将大型Polars DataFrame按列值拆分为指定数量的子DataFrame

拆分大型Polars DataFrame为指定数量的近似均等子DataFrame

问题背景

我有一个大型Polars DataFrame,希望根据数据规模将其拆分为n个自定义数量(例如2个、3个或5个)的子DataFrame。每个Identifier对应多条观测记录,之前的做法是按特定Identifier逐个拆分,但实际场景中Identifier数量庞大,无法手动指定,因此需要实现类似逻辑,将DataFrame拆分为近似均等的指定数量子DataFrame,同时尽量保证同一Identifier的记录不会被拆分到不同子集中。

方法1:按行索引直接拆分(快速高效,不保证Identifier完整性)

如果不需要确保同一Identifier的所有记录在同一个子DataFrame中,这种方法最简单直接,直接按总行数均分:

import polars as pl

# 示例DataFrame
df = pl.DataFrame({
    'Identifier': [1234,1234, 2345,2345, 3456,3456, 4567,4567],
    'DateColumn': ['2022-02-13','2022-02-14', '2022-02-13','2022-02-14',
                   '2022-02-13','2022-02-14', '2022-02-13','2022-02-14']
})

def split_df_by_rows(df, n_splits):
    total_rows = len(df)
    split_size = total_rows // n_splits
    splits = []
    start = 0
    # 处理行数无法整除的情况,前几个子集多分配一行
    for i in range(n_splits):
        end = start + split_size + (1 if i < total_rows % n_splits else 0)
        splits.append(df[start:end])
        start = end
    return splits

# 拆分为2个子DataFrame
split_dfs = split_df_by_rows(df, 2)
for i, sub_df in enumerate(split_dfs):
    print(f"子DataFrame {i+1}:")
    print(sub_df)

输出结果:

子DataFrame 1:
┌────────────┬────────────┐
│ Identifier ┆ DateColumn │
│ ---        ┆ ---        │
│ i64        ┆ str        │
╞════════════╪════════════╡
│ 1234       ┆ 2022-02-13 │
│ 1234       ┆ 2022-02-14 │
│ 2345       ┆ 2022-02-13 │
│ 2345       ┆ 2022-02-14 │
└────────────┴────────────┘
子DataFrame 2:
┌────────────┬────────────┐
│ Identifier ┆ DateColumn │
│ ---        ┆ ---        │
│ i64        ┆ str        │
╞════════════╪════════════╡
│ 3456       ┆ 2022-02-13 │
│ 3456       ┆ 2022-02-14 │
│ 4567       ┆ 2022-02-13 │
│ 4567       ┆ 2022-02-14 │
└────────────┴────────────┘

方法2:按Identifier分组后分配(保证同一Identifier在同一子集)

如果需要确保同一个Identifier的所有记录都在同一个子DataFrame中,先统计每个Identifier的行数,再将Identifier分配到不同子集,确保每个子集的总数据量近似均等:

import polars as pl

def split_df_by_identifier(df, n_splits, id_col='Identifier'):
    # 统计每个Identifier的记录数
    id_counts = df.group_by(id_col).agg(pl.count().alias('count'))
    # 计算累计行数,用于分配分组
    id_counts = id_counts.with_columns(pl.cumsum('count').alias('cum_count'))
    
    total_rows = df.height
    # 计算每个子集的行数阈值
    split_thresholds = [total_rows * (i+1)/n_splits for i in range(n_splits)]
    
    # 给每个Identifier分配对应的组号
    group_assignments = []
    current_group = 0
    for _, row in id_counts.iter_rows(named=True):
        while current_group < n_splits and row['cum_count'] > split_thresholds[current_group]:
            current_group += 1
        group_assignments.append((row[id_col], current_group))
    
    # 创建组号映射字典
    group_map = dict(group_assignments)
    # 给原DataFrame添加组号列
    df_with_group = df.with_columns(pl.col(id_col).map_dict(group_map).alias('split_group'))
    # 按组拆分并移除组号列
    split_dfs = [df_with_group.filter(pl.col('split_group') == i).drop('split_group') for i in range(n_splits)]
    return split_dfs

# 拆分为2个子DataFrame
split_dfs = split_df_by_identifier(df, 2)
for i, sub_df in enumerate(split_dfs):
    print(f"子DataFrame {i+1}:")
    print(sub_df)

当Identifier行数不均等时,比如修改示例DataFrame:

df = pl.DataFrame({
    'Identifier': [1234,1234,1234, 2345,2345, 3456],
    'DateColumn': ['2022-02-13','2022-02-14','2022-02-15', 
                   '2022-02-13','2022-02-14', '2022-02-13']
})

拆分后会自动调整分组,保证同一Identifier不被拆分:

子DataFrame 1:
┌────────────┬────────────┐
│ Identifier ┆ DateColumn │
│ ---        ┆ ---        │
│ i64        ┆ str        │
╞════════════╪════════════╡
│ 1234       ┆ 2022-02-13 │
│ 1234       ┆ 2022-02-14 │
│ 1234       ┆ 2022-02-15 │
└────────────┴────────────┘
子DataFrame 2:
┌────────────┬────────────┐
│ Identifier ┆ DateColumn │
│ ---        ┆ ---        │
│ i64        ┆ str        │
╞════════════╪════════════╡
│ 2345       ┆ 2022-02-13 │
│ 2345       ┆ 2022-02-14 │
│ 3456       ┆ 2022-02-13 │
└────────────┴────────────┘

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:20:54