Python JSON到具有嵌套列表的数据帧

Python JSON到具有嵌套列表的数据帧,python,json,pandas,Python,Json,Pandas,我运行下面的代码,它输出下面的json import requests url="xxxx" r = requests.request("GET", url, headers=headers, data=payload) j=r.json() recs = j['collection'] Json {'stationCode': 'NB001', 'summaries': [{'period': {'year': 2017}, 'rain

我运行下面的代码,它输出下面的json

import requests
url="xxxx"
r = requests.request("GET", url, headers=headers, data=payload)
j=r.json()

recs = j['collection']
Json

{'stationCode': 'NB001',
       'summaries': [{'period': {'year': 2017}, 'rainfall': 449},
        {'period': {'year': 2018}, 'rainfall': 352.4},
        {'period': {'year': 2019}, 'rainfall': 253.2},
        {'period': {'year': 2020}, 'rainfall': 283},
        {'period': {'year': 2021}, 'rainfall': 104.2}]},{'stationCode': 'NA003','summaries': [{'period': {'year': 2019}, 'rainfall': 58.2},{'period': {'year': 2020}, 'rainfall': 628.2},{'period': {'year': 2021}, 'rainfall': 120}]}
我需要如下输出到一个表中

尝试了下面的方法,我仍然可以通过添加多行来提取表,但只是想知道是否有更快的方法

df = json_normalize(recs)
df
使用:

或:

In [955]: %timeit f1()
385 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [969]: %timeit f2()
3.48 ms ± 224 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
分别解析
rec
dict,这应该更有效:

In [952]: def f1():
     ...:     s = []
     ...:     y = []
     ...:     r = []
     ...:     for k,v in recs[0].items():
     ...:         if k == 'stationCode':
     ...:             s.append(v)
     ...:     else:
     ...:         for i in v:
     ...:             y.append(i['period']['year'])
     ...:             r.append(i['rainfall'])
     ...:     s = s * len(y)
     ...:     df = pd.DataFrame({'stationCode': s, 'year': y, 'rainfall':r})
两者的计时:

In [955]: %timeit f1()
385 µs ± 20.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [969]: %timeit f2()
3.48 ms ± 224 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
您可以为元组中的每个条目迭代(您共享的数据是dict的元组):

替代解决方案:我喜欢,因为它对json中一些粗糙的嵌套选项非常有用。使用
jmespath
(它本身就是一种语言,有很多函数)的一个简短故事是,如果您正在访问一个键,则点进入播放,如果它是一个列表,则使用
[]
符号:

import jmespath
expression = jmespath.compile("""{stationcode:stationCode, 
                                  year: summaries[].period.year, 
                                  rainfall: summaries[].rainfall}""")

outcome = [pd.DataFrame(expression.search(entry)) for entry in recs]
pd.concat(outcome)

  stationcode  year  rainfall
0       NB001  2017     449.0
1       NB001  2018     352.4
2       NB001  2019     253.2
3       NB001  2020     283.0
4       NB001  2021     104.2
0       NA003  2019      58.2
1       NA003  2020     628.2
2       NA003  2021     120.0

只是你工具中的一个武器库,如果不能完全切断它的话。对于原始速度,内置的dict是王者。

+1然而,这就是我的意思。可以用几行额外的线路来完成。有直接上升法吗?没有这样的直接上升法。另一种方法是解析
recs
以获得直接的
dict
,而不是解析
df
@wwnde中的列。请检查我的更新答案。也有时间安排。谢谢@Mayank Porwal,Wemmy的回答很有说服力。解压嵌套的json列表。感谢您的帮助@wwnde。毫无疑问,共享的数据是一个dict元组。如果你能分享正确的json格式,那就更好了。我明白你的意思了。除非我给你一个网址。把它等同于一个变量,它就是一个元组?逗号实际上就是一个元组。看起来你复制了它的一小部分(虽然这很好),很好的一个@sammywemmyNice答案。但这比解析
recs
时的解决方案要慢;除此之外,json_normalize更为方便。如果您不介意将速度添加到您的解决方案中;这是一个很好的答案。@sammywemmy,很高兴发布一个问题。只是不想把它说出来,因为答案的质量很低。如果我有以下内容。如何将每个实体作为列获取?你似乎有相当多的武器库
import jmespath
expression = jmespath.compile("""{stationcode:stationCode, 
                                  year: summaries[].period.year, 
                                  rainfall: summaries[].rainfall}""")

outcome = [pd.DataFrame(expression.search(entry)) for entry in recs]
pd.concat(outcome)

  stationcode  year  rainfall
0       NB001  2017     449.0
1       NB001  2018     352.4
2       NB001  2019     253.2
3       NB001  2020     283.0
4       NB001  2021     104.2
0       NA003  2019      58.2
1       NA003  2020     628.2
2       NA003  2021     120.0