如何将pandas的数据框转换为嵌套字典

30

我正在使用 Python 3.6 和 Pandas 0.19.2,有一个如下所示的 DataFrame:

Name      Chain        Food       Healthy  

George    McDonalds    burger     False
George    KFC          chicken    False
John      Wendys       burger     False
John      McDonalds    salad      True

我希望将这个数据框转换为一个字典,其格式看起来如下:
health_data = {'George': {'McDonalds': {'Food': 'burger', 'Healthy':False},
                          'KFC':       {'Food': 'chicken', 'Healthy':False}},
               'John':   {'Wendys':    {'Food': 'burger', 'Healthy':False},
                          'McDonalds': {'Food': 'salad', 'Healthy': True}}}

我的想法是:

  1. 使用df.groupby将名称列分组
  2. 使用df.to_dict()将数据框转换为字典,例如:health_data = input_data.set_index('Chain').T.to_dict()

有何想法?感谢您的帮助。

2个回答

37

我认为你很接近了。

使用 groupbyto_dict

df = df.groupby('Name')[['Chain','Food','Healthy']]
       .apply(lambda x: x.set_index('Chain').to_dict(orient='index'))
       .to_dict()

print (df)
{'George': {'KFC': {'Healthy': False, 'Food': 'chicken'}, 
           'McDonalds': {'Healthy': False, 'Food': 'burger'}}, 
'John': {'McDonalds': {'Healthy': True, 'Food': 'salad'},
         'Wendys': {'Healthy': False, 'Food': 'burger'}}}

1
它是过滤列,但如果df中没有其他列,它可以简化为df.groupby('Name').apply(lambda x: x.set_index('Chain').to_dict(orient='index')).to_dict() - jezrael
1
我尝试做这个已经很久了,没想到把 .to_dict 放在 lambda 里面,谢谢一如既往的 Jozi :) - Umar.H
1
如果我想在apply中设置多个索引,有什么建议吗? - E. Zeytinci
@vhio - 因为需要按列“Chain”的嵌套字典的键。 - jezrael
2
@jezrael 如果还有一行数据是"George, McDonalds, chicken, False",你会如何调整代码呢?换句话说,由于"McDonalds"在"George"中出现了两次,所以索引值将会重复,这样就会抛出一个ValueError异常,因为'orient='index''要求索引必须唯一。 - Mike Lee
显示剩余3条评论

12

使用字典推导和 groupby 的解决方案:

{n: grp.loc[n].to_dict('index')
 for n, grp in df.set_index(['Name', 'Chain']).groupby(level='Name')}

{'George': {'KFC': {'Food': 'chicken', 'Healthy': False},
  'McDonalds': {'Food': 'burger', 'Healthy': False}},
 'John': {'McDonalds': {'Food': 'salad', 'Healthy': True},
  'Wendys': {'Food': 'burger', 'Healthy': False}}}

使用defaultdict的解决方案:

from collections import defaultdict

d = defaultdict(dict)

for i, row in df.iterrows():
    d[row.Name][row.Chain] = row.drop(['Name', 'Chain']).to_dict()

dict(d)

{'George': {'KFC': {'Food': 'chicken', 'Healthy': False},
  'McDonalds': {'Food': 'burger', 'Healthy': False}},
 'John': {'McDonalds': {'Food': 'salad', 'Healthy': True},
  'Wendys': {'Food': 'burger', 'Healthy': False}}}

2
喜欢使用iterrows和defaultdict,虽然比group by慢一点。这将允许您将多个循环链接在一起。另一种方法是使用多索引(但不适用于此示例)。 - Jon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接