【问题标题】:Aggregate Dataframe to Nested Dictionaries (python)将数据框聚合到嵌套字典(python)
【发布时间】:2021-11-05 05:15:10
【问题描述】:

我想将此数据框转换为字典,

import pandas as pd
df = pd.DataFrame({'Date': {0: 44197,1: 44197,2: 44197,3: 44197,4: 44198,5: 44198,6: 44198,7: 44198,8: 44197,9: 44197,10: 44197,11: 44197,12: 44198,13: 44198,14: 44198,15: 44198},
 'Product': {0: 'B',1: 'A',2: 'C',3: 'D',4: 'B',5: 'A',6: 'C',7: 'D',8: 'B',9: 'A',10: 'C',11: 'D',12: 'B',13: 'A',14: 'C',15: 'D'},
 'Seller': {0: 'XXX',1: 'XXX',2: 'XXX',3: 'XXX',4: 'XXX',5: 'XXX',6: 'XXX',7: 'XXX',8: 'YYY',9: 'YYY',10: 'YYY',11: 'YYY',12: 'YYY',13: 'YYY',14: 'YYY',15: 'YYY'},
 'Price': {0: 10,1: 25,2: 36,3: 14,4: 60,5: 31,6: 2,7: 7,8: 5,9: 9,10: 10,11: 26,12: 36,13: 78,14: 95,15: 100}})

这是数据框的样子,

我想根据卖方创建字典键,然后为每个日期分组产品作为键,所以 A 是键,价格是项目

订单是卖方 => 日期(因为将是 1000 个日期)=> 对于每个日期,您将拥有 4 种产品及其相应的价格。

有人知道怎么做吗?我的真实表是非常大的 100K 行,我的目标也是尽可能快。

我想要的结果如下所示:

{XXX:{"01/01/2021":{ A : Value1 , B : Value2 , C : Value3 , D : Value4 },"02/01/2021":{ .......}}, "YYY" : ....... }

【问题讨论】:

  • 期望输出的示例是什么??
  • {XXX:{"01/01/2021":{ A : Value1 , B : Value2 , C : Value3 , D : Value4 },"02/01/2021": .... ...}, "YYY" : ....... } @U12-Forward 看起来像这样
  • 这能回答你的问题吗? Convert a Pandas DataFrame to a dictionary
  • @Craicerjack 在发送更正之前阅读了我的帖子。
  • mods/close 选民注意:这不是this 的副本。这个问题要复杂得多。

标签: python pandas dataframe dictionary


【解决方案1】:
groupped_df = df.groupby(['Seller', 'Date']).apply(lambda x: x.set_index('Product').to_dict()).apply(lambda x: x['Price'])
desired_dict = {level: groupped_df.xs(level).to_dict() for level in groupped_df.index.levels[0]}

输出:

Out[100]: 
{'XXX': {44197: {'B': 10, 'A': 25, 'C': 36, 'D': 14},
  44198: {'B': 60, 'A': 31, 'C': 2, 'D': 7}},
 'YYY': {44197: {'B': 5, 'A': 9, 'C': 10, 'D': 26},
  44198: {'B': 36, 'A': 78, 'C': 95, 'D': 100}}}

在第一行,我们将分组并创建一个系列,其中卖家和日期是索引,值是所需的字典(最嵌套的字典)。这就是groupped_df = df.groupby(['Seller', 'Date']).apply(lambda x: x.set_index('Product').to_dict()) 发生的情况,但由于它在字典中创建了一些额外的“数据”,我还添加了.apply(lambda x: x['Price']) 以仅选择价格。

在第一行之后,groupped_df 如下所示:

Out[101]: 
Seller  Date 
XXX     44197     {'B': 10, 'A': 25, 'C': 36, 'D': 14}
        44198       {'B': 60, 'A': 31, 'C': 2, 'D': 7}
YYY     44197       {'B': 5, 'A': 9, 'C': 10, 'D': 26}
        44198    {'B': 36, 'A': 78, 'C': 95, 'D': 100}

第二行将多重索引转移到嵌套字典中,就像在this answer 中一样(注意在to_dict 中不需要'index' arg)

【讨论】:

  • 这太完美了,你知道如何将日期键从旧到新排序吗?
  • 它们是字典键,它们没有顺序。字典不包含它的键之间的任何顺序
  • @Roim 很好的答案!但自我认为 3.7 以来,已经订购了仅供参考的 python 字典。
  • @RicksupportsMonica 不知道这一点。谢谢。 @heunevy 我的错。我认为嵌套循环内应该有.sort_index,但我稍后会检查它并回复你
【解决方案2】:

使用pivot 重塑数据框,然后创建临时列并分配记录,最后在level=0 上使用unstack 并使用to_dict 创建字典

s = df.pivot(['Seller', 'Date'], 'Product', 'Price')
s.assign(r=s.to_dict('records'))['r'].unstack(0).to_dict()

{'XXX': {44197: {'A': 25, 'B': 10, 'C': 36, 'D': 14},
         44198: {'A': 31, 'B': 60, 'C': 2, 'D': 7}},
 'YYY': {44197: {'A': 9, 'B': 5, 'C': 10, 'D': 26},
         44198: {'A': 78, 'B': 36, 'C': 95, 'D': 100}}}

【讨论】:

  • 谢谢@RicksupportsMonica :-)
【解决方案3】:

首先,使用 set_index 将所需的嵌套索引设置为多索引:

>>> df.set_index(["Seller", "Date", "Product"])
                      Price
Seller Date  Product
XXX    44197 B           10
             A           25
             C           36
             D           14
       44198 B           60
             A           31
             C            2
             D            7
YYY    44197 B            5
             A            9
             C           10
             D           26
       44198 B           36
             A           78
             C           95
             D          100

然后使用 to_dict 方法将多索引转换为嵌套字典。每一列是dict中的一个key,multi-index转换成key,每个key都是一个tuple:

>>> df_transformed = df.set_index(["Seller", "Date", "Product"]).to_dict()
>>> df_transformed
{'Price': {('XXX', 44197, 'B'): 10, ('XXX', 44197, 'A'): 25, ('XXX', 44197, 'C'): 36, ('XXX', 44197, 'D'): 14, ('XXX', 44198, 'B'): 60, ('XXX', 44198, 'A'): 31, ('XXX', 44198, 'C'): 2, ('XXX', 44198, 'D'): 7, ('YYY', 44197, 'B'): 5, ('YYY', 44197, 'A'): 9, ('YYY', 44197, 'C'): 10, ('YYY', 44197, 'D'): 26, ('YYY', 44198, 'B'): 36, ('YYY', 44198, 'A'): 78, ('YYY', 44198, 'C'): 95, ('YYY', 44198, 'D'): 100}}

...单独捕获 Price 列(但在这种情况下,它当然是唯一的列):

>>> price_dict = df_transformed.to_dict()["Price"]
>>> price_dict
{('XXX', 44197, 'B'): 10, ('XXX', 44197, 'A'): 25, ('XXX', 44197, 'C'): 36, ('XXX', 44197, 'D'): 14, ('XXX', 44198, 'B'): 60, ('XXX', 44198, 'A'): 31, ('XXX', 44198, 'C'): 2, ('XXX', 44198, 'D'): 7, ('YYY', 44197, 'B'): 5, ('YYY', 44197, 'A'): 9, ('YYY', 44197, 'C'): 10, ('YYY', 44197, 'D'): 26, ('YYY', 44198, 'B'): 36, ('YYY', 44198, 'A'): 78, ('YYY', 44198, 'C'): 95, ('YYY', 44198, 'D'): 100}

请参阅来自 Martijn Pieters 的 this answer 以获取有关将元组键转换为嵌套字典的帮助。为了方便起见,我将在下面重复一遍,但这确实是 Pieters 的解决方案:

def nest(d: dict) -> dict:
    result = {}
    for key, value in d.items():
        target = result
        for k in key[:-1]:  # traverse all keys but the last
            target = target.setdefault(k, {})
        target[key[-1]] = value
    return result

最后:

>>> nest(price_dict)
{'XXX': {44197: {'B': 10, 'A': 25, 'C': 36, 'D': 14}, 44198: {'B': 60, 'A': 31, 'C': 2, 'D': 7}}, 'YYY': {44197: {'B': 5, 'A': 9, 'C': 10, 'D': 26}, 44198: {'B': 36, 'A': 78, 'C': 95, 'D': 100}}}

OP 在评论中提到日期的顺序很重要。需要注意的是,df_transformed 的多索引的顺序将决定最终嵌套字典的顺序。如果您想在将其转换为字典之前以不同的方式对其进行排序,请使用.sort_index()

【讨论】:

  • groupby 是正确的,这就是我试图在 dict 中达到的......
  • @heuveny 是的,虽然它实际上并不是真正的 groupby,但它是对索引的更改以匹配您想要的 dict 键的嵌套。
  • @heuveny 我终于完成了我的回答。抱歉,拖了一段时间!
猜你喜欢
  • 2022-12-05
  • 2022-01-17
  • 1970-01-01
  • 2021-03-20
  • 2021-04-03
  • 1970-01-01
  • 2021-06-11
  • 2015-10-06
  • 2019-10-03
相关资源
最近更新 更多