【问题标题】:How to create pandas dataframe from nested json with dictionary如何使用字典从嵌套 json 创建熊猫数据框
【发布时间】:2021-09-27 23:02:30
【问题描述】:

我正在尝试创建一个熊猫数据框表单 json 文件。我已经看到了这个问题的多种解决方案,它使用了 from_dict/json_normalize 的内置函数,但我无法将它应用到我的代码中。以下是我的数据在 json 文件中的结构:

     "data": [
   {
      "groups": {
         "data": [
               {
               "group": "Math",
               "year_joined": "2009"
               },
               {
               "group_name": "History",
               "year_joined": "2011"
               },
               {
               "group_name": "Biology",
               "year_joined": "2010"
               }
         ]
      },
      "id": "12512"
   },

当我尝试使用这样的 pandas 函数来规范化这些数据时:

path = 'mypath'
f = open(path)
data = json.load(f)

test = pd.json_normalize(
            data['data'], 
            errors='ignore') 

我刚收到这样的东西:

    id      groups.data
0   12512   [{'group_name': 'Math', 'year_joined': '2009', 'gr...
1   23172   [{'group_name': 'Chemistry', 'year_joined': '2005'...

我希望这些数据看起来像这样(解决方案 1):

    id      group     year_joined
0   12512   group1    year1
1   12512   group2    year2
2   12512   group3    year3

或者像这样(解决方案2):

    id      group                   year_joined
0   12512   group1,group2,group3    year1,year2,year3
1   23172   group4,group5           year4,year5

我怎样才能实现它?我尝试将“record_path”参数传递给“json_normalize”函数,但它没有任何改变。我尝试使用 'DataFrame.from_dict' 函数来解决这个问题,但我失败了。我能够获得解决方案 1 的唯一方法是创建多个循环,遍历 json 文件中的所有内容并将其添加到单独的列表中。它有点工作,但在更大的数据集上需要很多时间。

如何使用内置的 pandas 工具来处理嵌套在文件第 3 层中的字典作为上述文件?

提前感谢您的所有回复

【问题讨论】:

    标签: python pandas


    【解决方案1】:
    • 假设你有嵌套列表的 dict
      1. 从整体结构创建数据框
      2. explode()嵌入列表
      3. apply(pd.Series)扩展嵌套的dict
    d = {'groups': {'data': [{'group': 'Math', 'year_joined': '2009'},
       {'group_name': 'History', 'year_joined': '2011'},
       {'group_name': 'Biology', 'year_joined': '2010'}]},
     'id': '12512'}
    
    pd.json_normalize(d).explode("groups.data").reset_index(drop=True).pipe(
        lambda d: d["id"].to_frame().join(d["groups.data"].apply(pd.Series))
    )
    
    
    id group year_joined group_name
    0 12512 Math 2009 nan
    1 12512 nan 2011 History
    2 12512 nan 2010 Biology

    【讨论】:

      【解决方案2】:

      您需要从data 字典中收集信息

      解决方案 1

      d = {}
      for group in data["data"]:
          groups = [x["group_name"] for x in group['groups']["data"]]
          d['id'] = d.get('id', []) + [group['id']] * len(groups)
          d['group'] = d.get('group', []) + groups
          d['year_joined'] = d.get('year_joined', []) + [x["year_joined"] for x in group['groups']["data"]]
      
      df = pd.DataFrame(d)
      

      输出

            id      group year_joined
      0  12512       Math        2009
      1  12512    History        2011
      2  12512    Biology        2010
      3  23172  Chemistry        2007
      4  23172  Economics        2008
      

      解决方案 2

      d = {}
      for group in data["data"]:
          d['id'] = d.get('id', []) + [group['id']]
          d['group'] = d.get('group', []) + [','.join(x["group_name"] for x in group['groups']["data"])]
          d['year_joined'] = d.get('year_joined', []) + [','.join(x["year_joined"] for x in group['groups']["data"])]
      
      df = pd.DataFrame(d)
      

      输出

            id                 group     year_joined
      0  12512  Math,History,Biology  2009,2011,2010
      1  23172   Chemistry,Economics       2007,2008
      

      【讨论】:

        【解决方案3】:

        这似乎适用于您的示例:

        data = [ # Original data from question
           {
              "groups": {
                 "data": [
                       {
                       "group": "Math",
                       "year_joined": "2009"
                       },
                       {
                       "group_name": "History",
                       "year_joined": "2011"
                       },
                       {
                       "group_name": "Biology",
                       "year_joined": "2010"
                       }
                 ]
              },
              "id": "12512"
           },
        ]
        # Use the record_path to extract the list we are interested in, and make sure we retain ID
        df = pandas.json_normalize(data, record_path=['groups','data'], meta=['id'])
        # Combine the group and group_name columns into a single column as they appear mutually exclusive
        df["group"] = df["group_name"].fillna(df["group"])
        # Discard the now unnecessary column
        df.drop(columns='group_name', inplace=True)
        

        它给出:

        year_joined group id
        0 2009 Math 12512
        1 2011 History 12512
        2 2010 Biology 12512

        创建第二个数据框:

        df.groupby(['id']).agg({'year_joined':list,'group':list})
        
        id year_joined group
        12512 ['2009', '2011', '2010'] ['Math', 'History', 'Biology']

        【讨论】:

          猜你喜欢
          • 2021-11-28
          • 1970-01-01
          • 2019-01-11
          • 2023-01-14
          • 2017-01-01
          • 2021-02-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多