如何使用pandas.io.json.read_json加载嵌套在JSON中results层级的DataFrame?
我明白你想跳过繁琐的urllib+json组合,用更简洁的pandas原生方法直接从URL加载嵌套在results层级里的数据为DataFrame的需求。先给你解释下为什么直接调用pandas.io.json.read_json(url_reporter)会报错:
你目标JSON的顶层是包含more(布尔值)和results(数组)的混合结构,而read_json默认的orient="columns"参数,期望顶层是能直接映射为DataFrame列的格式(比如键为列名的对象,或者直接是数组)。这种混合结构不符合默认解析规则,所以抛出了ValueError: Expected object or value;而url_partner的JSON虽然能被读取,但返回的是把results作为单列的扁平化DataFrame,每个单元格都是嵌套JSON数据,这显然不是你想要的结果。
遗憾的是,pandas的read_json目前没有内置参数可以直接指定读取嵌套JSON中的特定层级,不过我们可以用更简洁的写法实现需求,不用冗长的低级操作:
方法1:结合requests(最简洁)
如果你的环境允许安装requests库(比urllib更易用),可以这样写:
import pandas as pd import requests url_reporter = "https://comtrade.un.org/Data/cache/reporterAreas.json" url_partner = "https://comtrade.un.org/Data/cache/partnerAreas.json" # 读取JSON并直接提取results层级转成DataFrame df_reporter = pd.DataFrame(requests.get(url_reporter).json()['results']) df_partner = pd.DataFrame(requests.get(url_partner).json()['results'])
方法2:只用pandas+urllib(无额外依赖)
如果不想引入新依赖,也可以简化你原来的代码:
import pandas as pd import urllib.request import json url_reporter = "https://comtrade.un.org/Data/cache/reporterAreas.json" with urllib.request.urlopen(url_reporter) as response: df_reporter = pd.DataFrame(json.load(response)['results'])
方法3:强行用pandas.io.json.read_json(满足你的执念)
如果你一定要用pandas.io.json.read_json,可以把提取出的results数组转成JSON字符串再传入:
import pandas as pd import urllib.request import json url_reporter = "https://comtrade.un.org/Data/cache/reporterAreas.json" with urllib.request.urlopen(url_reporter) as response: json_content = json.load(response) # 将results数组转为JSON字符串后,用read_json读取 df_reporter = pd.io.json.read_json(json.dumps(json_content['results']))
另外,对于url_partner那种能被read_json直接读取但返回扁平化DataFrame的情况,也可以直接提取results列并转为DataFrame:
df_partner = pd.io.json.read_json(url_partner)['results'].apply(pd.Series) # 或者用json_normalize处理更复杂的嵌套结构 df_partner = pd.json_normalize(pd.io.json.read_json(url_partner)['results'])
本质上,这些方法都是先获取完整的JSON对象,提取出目标层级的数组后再转为DataFrame——思路和你原来的低级方法一致,但写法更简洁,也更贴合pandas的使用习惯。
内容的提问来源于stack exchange,提问作者Paul Rougieux

