熊猫 groupby 到嵌套的 json

Posted

技术标签:

【中文标题】熊猫 groupby 到嵌套的 json【英文标题】:pandas groupby to nested json 【发布时间】:2014-08-13 23:22:04 【问题描述】:

我经常使用 pandas groupby 来生成堆叠表格。但后来我经常想将生成的嵌套关系输出到 json。有没有办法从它产生的堆叠表中提取嵌套的 json 文件?

假设我有一个像这样的df:

year office candidate  amount
2010 mayor  joe smith  100.00
2010 mayor  jay gould   12.00
2010 govnr  pati mara  500.00
2010 govnr  jess rapp   50.00
2010 govnr  jess rapp   30.00

我能做到:

grouped = df.groupby('year', 'office', 'candidate').sum()

print grouped
                       amount
year office candidate 
2010 mayor  joe smith   100
            jay gould    12
     govnr  pati mara   500
            jess rapp    80

漂亮!当然,我真正想做的是通过沿 grouped.to_json 行的命令获取嵌套的 json。但该功能不可用。任何解决方法?

所以,我真正想要的是:

"2010": "mayor": [
                    "joe smith": 100,
                    "jay gould": 12
                   ]
         , 
          "govnr": [
                     "pati mara":500, 
                     "jess rapp": 80
                    ]
          

不要

【问题讨论】:

上面的代码实际上并不能工作,因为金额列(例如'$30')是字符串,所以添加为字符串而不是数字。另外,不清楚你想要什么 json 输出,为什么 to_json 为你工作? @AndyHayden 好点。我已经编辑修复/澄清。 @Don 有什么解决办法吗? @skycrew 请参阅下面 chrisb 的回答。 【参考方案1】:

我认为 pandas 没有内置任何东西来创建数据的嵌套字典。下面是一些通常适用于具有 MultiIndex 的系列的代码,使用 defaultdict

嵌套代码遍历 MultIndex 的每一层,将层添加到字典中,直到最深的层被分配给 Series 值。

In  [99]: from collections import defaultdict

In [100]: results = defaultdict(lambda: defaultdict(dict))

In [101]: for index, value in grouped.itertuples():
     ...:     for i, key in enumerate(index):
     ...:         if i == 0:
     ...:             nested = results[key]
     ...:         elif i == len(index) - 1:
     ...:             nested[key] = value
     ...:         else:
     ...:             nested = nested[key]

In [102]: results
Out[102]: defaultdict(<function <lambda> at 0x7ff17c76d1b8>, 2010: defaultdict(<type 'dict'>, 'govnr': 'pati mara': 500.0, 'jess rapp': 80.0, 'mayor': 'joe smith': 100.0, 'jay gould': 12.0))

In [106]: print json.dumps(results, indent=4)

    "2010": 
        "govnr": 
            "pati mara": 500.0, 
            "jess rapp": 80.0
        , 
        "mayor": 
            "joe smith": 100.0, 
            "jay gould": 12.0
        
    

【讨论】:

@chrisb 我正在尝试调整您的答案以解决类似问题,但被 grouped.intertuples() 绊倒:***.com/questions/37819622/… 这只能用于三个级别,如果还有更多呢?【参考方案2】:

我知道这是一个老问题,但我最近遇到了同样的问题。这是我的解决方案。我从 chrisb 的例子中借了很多东西(谢谢!)。

这样做的好处是您可以传递一个 lambda 以从您想要的任何可枚举对象以及每个组中获取最终值。

from collections import defaultdict

def dict_from_enumerable(enumerable, final_value, *groups):
    d = defaultdict(lambda: defaultdict(dict))
    group_count = len(groups)
    for item in enumerable:
        nested = d
        item_result = final_value(item) if callable(final_value) else item.get(final_value)
        for i, group in enumerate(groups, start=1):
            group_val = str(group(item) if callable(group) else item.get(group))
            if i == group_count:
                nested[group_val] = item_result
            else:
                nested = nested[group_val]
    return d

在问题中,你可以这样称呼这个函数:

dict_from_enumerable(grouped.itertuples(), 'amount', 'year', 'office', 'candidate')

第一个参数也可以是一个数据数组,甚至不需要 pandas。

【讨论】:

【参考方案3】:

我查看了上面的解决方案,发现它仅适用于 3 级嵌套。此解决方案适用于任意数量的级别。

import json
levels = len(grouped.index.levels)
dicts = [ for i in range(levels)]
last_index = None

for index,value in grouped.itertuples():

    if not last_index:
        last_index = index

    for (ii,(i,j)) in enumerate(zip(index, last_index)):
        if not i == j:
            ii = levels - ii -1
            dicts[:ii] =  [ for _ in dicts[:ii]]
            break

    for i, key in enumerate(reversed(index)):
        dicts[i][key] = value
        value = dicts[i]

    last_index = index


result = json.dumps(dicts[-1])

【讨论】:

喜欢这个答案。仅供参考:最新版本的 pandas 将第 2 行替换为 """levels = grouped.ndim"""【参考方案4】:

这里是这个问题的通用递归解决方案:

def df_to_dict(df):
    if df.ndim == 1:
        return df.to_dict()

    ret = 
    for key in df.index.get_level_values(0):
        sub_df = df.xs(key)
        ret[key] = df_to_dict(sub_df)
    return ret

【讨论】:

此解决方案不根据数据框中的第一列进行分组

以上是关于熊猫 groupby 到嵌套的 json的主要内容,如果未能解决你的问题,请参考以下文章

熊猫 groupby 和 qcut

Seaborn通过多个groupby绘制熊猫数据框

熊猫 groupby.apply 到 pyspark

忽略熊猫 groupby 组中的 NaN 的标准错误

如何在熊猫中执行选择性 groupby().count()?

熊猫如何使用 groupby 将 NaN 值替换为平均值 [重复]