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

如何将Polars DataFrame转换为指定结构的嵌套字典?

问题描述

我有如下结构的Polars DataFrame:

import polars as pl

df = pl.DataFrame(
    {
        "file": ["A", "A", "A", "B", "B", "B"],
        "user": ["u1", "u2", "u3", "u1", "u2", "u3"],
        "data1": [1, 2, 3, 4, 5, 6],
        "data2": [7, 8, 9, 10, 11, 12],
        "data3": [13, 14, 15, 16, 17, 18],
    }
)

输出的DataFrame样式:

shape: (6, 5)
┌──────┬──────┬───────┬───────┬───────┐
│ file ┆ user ┆ data1 ┆ data2 ┆ data3 │
│ ---  ┆ ---  ┆ ---   ┆ ---   ┆ ---   │
│ str  ┆ str  ┆ i64   ┆ i64   ┆ i64   │
╞══════╪══════╪═══════╪═══════╪═══════╡
│ A    ┆ u1   ┆ 1     ┆ 7     ┆ 13    │
│ A    ┆ u2   ┆ 2     ┆ 8     ┆ 14    │
│ A    ┆ u3   ┆ 3     ┆ 9     ┆ 15    │
│ B    ┆ u1   ┆ 4     ┆ 10    ┆ 16    │
│ B    ┆ u2   ┆ 5     ┆ 11    ┆ 17    │
│ B    ┆ u3   ┆ 6     ┆ 12    ┆ 18    │
└──────┴──────┴───────┴───────┴───────┘

希望转换为以下嵌套字典格式:

{
    'file': {
        'A': {
            'user': {
                'u1': {'data1': 1, 'data2': 7, 'data3': 13},
                'u2': {'data1': 2, 'data2': 8, 'data3': 14},
                'u3': {'data1': 3, 'data2': 9, 'data3': 15}
            }
        },
        'B': {
            'user': {
                'u1': {'data1': 4, 'data2': 10, 'data3': 16},
                'u2': {'data1': 5, 'data2': 11, 'data3': 17},
                'u3': {'data1': 6, 'data2': 12, 'data3': 18}
            }
        }
    }
}

我尝试过两种方法:

  1. 使用rows_by_key:
df.rows_by_key(key=["file", "user"], unique=True, named=True)

得到的是元组为键的字典,不符合需求:

{('A', 'u1'): {'data1': 1, 'data2': 7, 'data3': 13},
 ('A', 'u2'): {'data1': 2, 'data2': 8, 'data3': 14},
 ('A', 'u3'): {'data1': 3, 'data2': 9, 'data3': 15},
 ('B', 'u1'): {'data1': 4, 'data2': 10, 'data3': 16},
 ('B', 'u2'): {'data1': 5, 'data2': 11, 'data3': 17},
 ('B', 'u3'): {'data1': 6, 'data2': 12, 'data3': 18}}
  1. 手动循环分组:
d = {}
for file, df_file in df.group_by("file", maintain_order=True):
    d_user = {}
    for user, df_file_user in df_file.group_by("user", maintain_order=True):
        d_user[user[0]] = df_file_user.drop("file", "user").to_dicts()[0]
    d[file[0]] = {"user": d_user}
print({"file": d})

这个方法能得到正确结果,但流程繁琐,想知道有没有更直接的实现方式。

解决方案

方法1:Polars原生嵌套聚合+字典转换

通过两层分组聚合,将数据打包成结构体后直接转换为目标格式:

final_dict = (
    df
    .group_by("file", "user", maintain_order=True)
    .agg(pl.col("data1", "data2", "data3").first())
    .group_by("file", maintain_order=True)
    .agg(
        pl.struct(pl.col("user"), pl.struct(pl.col("data1", "data2", "data3")).alias("data"))
        .map_elements(lambda x: {u: d for u, d in zip(x["user"], x["data"])}, return_dtype=pl.Object)
        .alias("user")
    )
    .to_dict(as_series=False)
)

该方法全程通过Polars的聚合和映射操作完成,避免手动循环,代码更简洁高效。

方法2:基于rows_by_key的二次处理

如果已经通过rows_by_key得到元组键的字典,可利用defaultdict快速嵌套:

from collections import defaultdict

raw_dict = df.rows_by_key(key=["file", "user"], unique=True, named=True)

nested_dict = defaultdict(dict)
for (file, user), data in raw_dict.items():
    if file not in nested_dict:
        nested_dict[file] = {"user": {}}
    nested_dict[file]["user"][user] = data

final_dict = {"file": nested_dict}

这种方式在已有rows_by_key结果的基础上,用简单的循环和字典操作完成结构转换,代码量极少。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:39:53