如何将包含嵌套对象的JSON文件读取为pandas DataFrame?

63
我很好奇如何使用pandas来读取以下结构的嵌套JSON数据:
{
    "number": "",
    "date": "01.10.2016",
    "name": "R 3932",
    "locations": [
        {
            "depTimeDiffMin": "0",
            "name": "Spital am Pyhrn Bahnhof",
            "arrTime": "",
            "depTime": "06:32",
            "platform": "2",
            "stationIdx": "0",
            "arrTimeDiffMin": "",
            "track": "R 3932"
        },
        {
            "depTimeDiffMin": "0",
            "name": "Windischgarsten Bahnhof",
            "arrTime": "06:37",
            "depTime": "06:40",
            "platform": "2",
            "stationIdx": "1",
            "arrTimeDiffMin": "1",
            "track": ""
        },
        {
            "depTimeDiffMin": "",
            "name": "Linz/Donau Hbf",
            "arrTime": "08:24",
            "depTime": "",
            "platform": "1A-B",
            "stationIdx": "22",
            "arrTimeDiffMin": "1",
            "track": ""
        }
    ]
}

这里将数组保留为json格式。我更希望它能展开成列。
pd.read_json("/myJson.json", orient='records')

编辑

感谢第一次的回答。 我应该修改一下我的问题: 对数组中嵌套属性的展平并不是强制性的。 只需要将df.locations['name']连接起来,就可以得到[A, B, C]。

我的文件包含多个JSON对象(每行一个),我想保留number、date、name和locations列。然而,我需要将locations连接起来。

allLocations = ""
isFirst = True
for location in result.locations:
    if isFirst:
        isFirst = False
        allLocations = location['name']
    else:
        allLocations += "; " + location['name']
allLocations

我的方法在这里似乎不够高效/不符合pandas的风格。

最简单的方法,您可以在这里检查我的答案。 - Yashraj Nigam
4个回答

76
您可以使用 json_normalize
import json

with open('myJson.json') as data_file:    
    data = json.load(data_file)  

df = pd.json_normalize(data, 'locations', ['date', 'number', 'name'], 
                    record_prefix='locations_')
print (df)
  locations_arrTime locations_arrTimeDiffMin locations_depTime  \
0                                                        06:32   
1             06:37                        1             06:40   
2             08:24                        1                     

  locations_depTimeDiffMin           locations_name locations_platform  \
0                        0  Spital am Pyhrn Bahnhof                  2   
1                        0  Windischgarsten Bahnhof                  2   
2                                    Linz/Donau Hbf               1A-B   

  locations_stationIdx locations_track number    name        date  
0                    0          R 3932         R 3932  01.10.2016  
1                    1                         R 3932  01.10.2016  
2                   22                         R 3932  01.10.2016 

编辑:

您可以使用 read_json 函数来解析 name,再通过 DataFrame 构造函数创建数据帧,最后使用 groupby 函数并应用 join 函数:

df = pd.read_json("myJson.json")
df.locations = pd.DataFrame(df.locations.values.tolist())['name']
df = df.groupby(['date','name','number'])['locations'].apply(','.join).reset_index()
print (df)
        date    name number                                          locations
0 2016-01-10  R 3932         Spital am Pyhrn Bahnhof,Windischgarsten Bahnho... 

我看到了。谢谢。哪些列需要放入 ['date','number','name'] 数组中?这对我来说还有点不清楚。对我而言,只需将所有位置的名称连接为字符串并保留该列即可。 - Georg Heiler
@vishnuprashanth - 这是一个难题,你认为是 None 还是 np.nan 值?它是否会移除 json_normalize 函数? - jezrael
@jezrael我有几行包含值“date”:'x','name':'y','locations':[]和其他包含“locations”值的行。当我应用json_normalize时,它会返回仅包含位置值的行,并删除具有“位置”:[]的行。我认为这是none。 [] - vishnu prashanth
@vishnuprashanth - 那么需要将json_normalize更改为pd.DataFrame构造函数。 - jezrael
@jezrael 这太棒了!我需要知道如何对数组中的数组执行此方法,类似于 MongoDB 中的 $unwind。这可能吗? - Matt Lightbourn
显示剩余10条评论

5

如果有人在阅读笔记本时发现这一点,另一个选项是将文件读取为df。

df = pd.read_json('filename.json')
df2 = pd.DataFrame.from_records(df['nest_level_1']['nest_level_2'])

愉快的编码


1

一个可能的替代 pandas.json_normalize 的方法是从嵌套字典中仅提取所选键和值来构建自己的数据框。这样做的主要原因是因为 json_normalize 对于非常大的 json 文件速度较慢(并且可能不总是产生您想要的输出)。

因此,这里介绍了一种使用 glom 在 pandas 中展开嵌套字典的替代方法。目的是从嵌套字典中提取所选键和值,并将它们保存在 pandas 数据框的单独列中:

以下是逐步指南:https://medium.com/@enrico.alemani/flatten-nested-dictionaries-in-pandas-using-glom-7948345c88f5

import pandas as pd
from glom import glom
from ast import literal_eval


target = {
    "number": "",
    "date": "01.10.2016",
    "name": "R 3932",
    "locations":
        {
            "depTimeDiffMin": "0",
            "name": "Spital am Pyhrn Bahnhof",
            "arrTime": "",
            "depTime": "06:32",
            "platform": "2",
            "stationIdx": "0",
            "arrTimeDiffMin": "",
            "track": "R 3932"
        }
}   



# Import data
df = pd.DataFrame([str(target)], columns=['target'])

# Extract id keys and save value into a separate pandas column
df['id'] = df['target'].apply(lambda row: glom(literal_eval(row), 'locations.name'))

0

我有一个多行的Json,每一行都有一个Json对象

{'a':'b','scope':{'eid':123213}} {'a':'d','scope':{'eid':1343213}}

没有逗号分隔。每行都是独立的。

我使用以下逻辑来读取嵌套结构

threshold = pd.read_json(r"/content/data.json",lines=True)

threshold = pd.read_json(r"/content/data.json",lines=True)
threshold['entityId'] = pd.DataFrame.from_records(threshold['scope'])['entityId']
threshold.head()

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