【问题标题】:create nested JSON from Pandas DataFrame with grouped rows as attributes inside deepest nest从 Pandas DataFrame 创建嵌套 JSON,将分组行作为最深嵌套内的属性
【发布时间】:2020-09-09 15:41:28
【问题描述】:

我正在寻找一种解决方案来构建具有最后三列 "name""color""amount" 的嵌套 dict / JSON 作为 “产品” 列表中的属性。 cat1-cat3 列中的值应该是键。

提供的 DataFrame 如下所示:

import pandas as pd

df = pd.DataFrame({
    'cat1': ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C'],
    'cat2': ['BB', 'BB', 'BC', 'BB', 'BB', 'BB', 'BC', 'BC'],
    'cat3': ['CC', 'CC', 'CD', 'CD', 'CD', 'CC', 'CD', 'CE'],
    'name': ['P1', 'P2', 'P3', 'P1', 'P4', 'P1', 'P3','P6'],
    'color': ['red', 'blue', 'green', 'green', 'yellow', 'red', 'blue', 'blue']
    'amount': [132, 51, 12, 421, 55, 11, 123, 312]
})

这将是所需的输出:

{
   "A":{
      "BB":{
         "CC":{
            "products":[
               {
                  "name":"P1",
                  "color":"red",
                  "amount":132
               },
               {
                  "name":"P2",
                  "color":"blue",
                  "amount":51
               }
            ]
         }
      },
      "BC":{
         "CD":{
            "products":[
               {
                  "name":"P3",
                  "color":"green",
                  "amount":12
               }
            ]
         }
      }
   },
   "B":{
      "BB":{
         "CD":{
            "products":[
               {
                  "name":"P1",
                  "color":"green",
                  "amount":421
               },
               {
                  "name":"P4",
                  "color":"yellow",
                  "amount":55
               }
            ]
         }
      }
   },
   "C":{
      "BB":{
         "CC":{
            "products":[
               {
                  "name":"P1",
                  "color":"red",
                  "amount":11
               }
            ]
         }
      },
      "BC":{
         "CD":{
            "products":[
               {
                  "name":"P3",
                  "color":"blue",
                  "amount":123
               }
            ]
         },
         "CE":{
            "products":[
               {
                  "name":"P6",
                  "color":"blue",
                  "amount":312
               }
            ]
         }
      }
   }
}

@BEN_YO 为这个问题提供了一个 recursive solution,但没有内部 products 部分。

所以我实际上正在寻找这种方法与内部列表的改编:

def recur_dictify(frame):
     if len(frame.columns) == 1:
         if frame.values.size == 1: return frame.values[0][0]
         return frame.values.squeeze()
     grouped = frame.groupby(frame.columns[0])
     d = {k: recur_dictify(g.iloc[:,1:]) for k,g in grouped}
     return d
     
recur_dictify(df)

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    如果其他方法没问题,你可以试试下面的,虽然有点脏(你可以尝试优化它)

    cols = ['name','color','amount']
    u = df[df.columns.difference(cols)].join(df[cols].agg(dict,1).rename('d'))
    v = (u.groupby(['cat1','cat2','cat3'])['d'].agg(list).reset_index("cat3"))
    
    v = v.groupby(v.index).apply(lambda x: dict(zip(x['cat3'],x['d'])))
    v.index = pd.MultiIndex.from_tuples(v.index,names=['cat1','cat2'])
    d = v.unstack(0).to_dict()
    

    print(d)
    {'A': {'BB': {'CC': [{'amount': 132, 'color': 'red', 'name': 'P1'},
                         {'amount': 51, 'color': 'blue', 'name': 'P2'}]},
           'BC': {'CD': [{'amount': 12, 'color': 'green', 'name': 'P3'}]}},
     'B': {'BB': {'CD': [{'amount': 421, 'color': 'green', 'name': 'P1'},
                         {'amount': 55, 'color': 'yellow', 'name': 'P4'}]},
           'BC': nan},
     'C': {'BB': {'CC': [{'amount': 11, 'color': 'red', 'name': 'P1'}]},
           'BC': {'CD': [{'amount': 123, 'color': 'blue', 'name': 'P3'}],
                  'CE': [{'amount': 312, 'color': 'blue', 'name': 'P6'}]}}}
    

    【讨论】:

      【解决方案2】:

      我们可以在cat1cat2cat3groupby 并根据分组的类别递归地构建字典:

      def set_val(d, k, v):
          if len(k) == 1:
              d[k[0]] = v
          else:
              d[k[0]] = set_val(d.get(k[0], {}), k[1:], v)
          return d
      
      
      dct = {}
      for k, g in df.groupby(['cat1', 'cat2', 'cat3']):
          set_val(dct, k, {'products': g[['name', 'color', 'amount']].to_dict('r')})
      

      print(dct)
      
      {'A': {'BB': {'CC': {'products': [{'amount': 132, 'color': 'red', 'name': 'P1'},
                                        {'amount': 51, 'color': 'blue', 'name': 'P2'}]}},
             'BC': {'CD': {'products': [{'amount': 12, 'color': 'green', 'name': 'P3'}]}}},
       'B': {'BB': {'CD': {'products': [{'amount': 421, 'color': 'green', 'name': 'P1'},
                                        {'amount': 55, 'color': 'yellow', 'name': 'P4'}]}}},
       'C': {'BB': {'CC': {'products': [{'amount': 11, 'color': 'red', 'name': 'P1'}]}},
             'BC': {'CD': {'products': [{'amount': 123, 'color': 'blue', 'name': 'P3'}]},
                    'CE': {'products': [{'amount': 312, 'color': 'blue', 'name': 'P6'}]}}}}
      

      【讨论】:

        【解决方案3】:

        这是一个改编自Shubham Sharma's great Solution通用方法

        def gen_nested_dict(dataframe, group, inner_key, inner_dict):
            def set_val(d, k2, v):
                if len(k2) == 1:
                    d[k2[0]] = v
                else:
                    d[k2[0]] = set_val(d.get(k2[0], {}), k2[1:], v)
                return d
        
            dct = {}
            for k, g in dataframe.groupby(group):
                set_val(dct, k, {inner_key: g[inner_dict].to_dict('records')})
        
            return dct
        
         mydct = gen_nested_dict(df, ['cat1', 'cat2', 'cat3'], 'products', ['name', 'color', 'amount'])
        

        【讨论】:

        • 不错的抽象 :)
        猜你喜欢
        • 2014-02-24
        • 1970-01-01
        • 1970-01-01
        • 2020-06-15
        • 2019-06-09
        • 2020-09-29
        • 2021-09-14
        • 2014-06-27
        • 1970-01-01
        相关资源
        最近更新 更多