为特定路径平展Pandas JSON Dataframe

时间:2018-03-21 16:48:21

标签: python-3.x pandas

我有以下JSON

ds = [{
    "name": "groupA",
    "subGroups": [{
        "subGroup": 1,
        "categories": [{
                "category1": {
                    "value": 10
                }
            },
            {
                "category2": {}
            },
            {
                "category3": {}
            }
        ]
    }]
},
{
    "name": "groupB",
    "subGroups": [{
        "subGroup": 1,
        "categories": [{
                "category1": {
                    "value": 500
                }
            },
            {
                "category2": {}
            },
            {
                "category3": {}
            }
        ]
    }]
}]

我可以通过以下方式获取所有类别的数据框:

json_normalize(ds, record_path=["subGroups", "categories"], meta=['name', ['subGroups', 'subGroup']], record_prefix='cat.')

这会给我:

  cat.category1 cat.category2   cat.category3 subGroups.subGroup    name
    0   {'value': 10}   NaN             NaN           1    groupA
    1   NaN             {}              NaN           1    groupA
    2   NaN             NaN             {}            1    groupA
    3   {'value': 500}  NaN             NaN           1    groupB
    4   NaN             {}              NaN           1    groupB
    5   NaN             NaN             {}            1    groupB

但是,我根本不关心第2类和第3类。我只关心第1类。 所以我喜欢这样的东西:         cat.category1 subGroups.subGroup名称     0 {'值':10} 1 groupA     1 {' value':500} 1 groupB

我有什么想法吗?

更好的是,我真的想要类别1中的价值。如下所示:

    cat.category1.value subGroups.subGroup  name
0   10                  1                   groupA
1   500                 1                   groupB

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

问题是category1不被json_normalize视为记录。记录的非正式定义是字典中映射到dicts列表的关键。您无法通过category1参数访问value(因此record_path),因为它不会映射到词典列表。

这是我能找到的最佳解决方案:

import pandas as pd
df = pd.io.json.json_normalize(ds,
                          record_path=['subGroups', 'categories'],
                          errors='ignore',
                          meta=['name', 
                                ['subGroups', 'subGroup'],
                               ],
                          record_prefix='cat.')
df = df.drop(['cat.category2', 'cat.category3'], axis=1)
for i in range(df.shape[0]):
    row = df.at[i, 'cat.category1']
    if isinstance(row, dict) and 'value' in row:
        df.at[i, 'cat.category1'] = row['value']
    else:
        df.at[i, 'cat.category1'] = np.nan

# EDIT: if you want to remove rows for which cat.category1 column has NAN values
df = df[pd.notnull(df['cat.category1'])]

df的输出是数据帧的理想形式。

另一方面,如果你的JSON结构看起来像这样(注意value dict周围的列表括号):

ds = [{
    "name": "groupA",
    "subGroups": [{
        "subGroup": 1,
        "categories": [{
            "category1": [{
                "value": 10
            }]
        }]
    }]
},
{
    "name": "groupB",
    "subGroups": [{
        "subGroup": 1,
        "categories": [{
            "category1": [{
                "value": 500
            }]
        }]
    }]
}]

您可以像这样使用json_normalize

df = pd.io.json.json_normalize(ds,
                          record_path=['subGroups', 'categories', 'category1'],
                          errors='ignore',
                          meta=['name', 
                                ['subGroups', 'subGroup'],
                               ],
                          record_prefix='cat.')

你会得到这个:

cat.value   name    subGroups.subGroup
    10     groupA    1
    500    groupB    1

答案 1 :(得分:-1)

尝试使用YAML为此目的,它有yaml转储以人类可读的格式写输出和其他函数重写json中的输出。

点击此处查看基本视频教程:

https://www.youtube.com/watch?v=hSuHnuNC8L4