前言:Json数据介绍Json是一个利用及其宽泛的用来传输和替换数据的格局,它被利用在数据库中,也被用于API申请后果数据集中。
尽管它利用宽泛,机器很容易浏览且节俭空间,然而却不利于人来浏览和进一步做数据分析,因而通常状况下须要在获取json数据后,将其转化为表格格局的数据,以不便人来浏览和了解。
常见的Json数据格式有2种,均以键值对的模式存储数据,只是包装数据的办法有所差别:
a. 个别JSON对象采纳{}将键值对数据括起来,有时候会有多层{}
b. JSON对象列表采纳[]将JSON对象括起来,造成一个JSON对象的列表,JSON对象中同样会有多层{},也会有[]呈现,造成嵌套列表
这篇文章次要讲述pandas内置的Json数据转换方法json_normalize(),它能够对以上两种Json格局的数据进行解析,最终生成DataFrame,进而对数据进行更多操作。本文的次要解构如下:
解析一个最根本的Json- 解析一个带有多层数据的Json- 解析一个带有嵌套列表的Json- 当Key不存在时如何疏忽零碎报错- 应用sep参数为嵌套Json的Key设置分隔符- 为嵌套列表数据和元数据增加前缀- 通过URL获取Json数据并进行解析- 探索:解析带有多个嵌套列表的Jsonjson_normalize()函数参数解说
在进行代码演示前先导入相应依赖库,未装置pandas库的请自行装置(此代码在Jupyter Notebook环境中运行)。
from pandas import json_normalizeimport pandas as pd1. 解析一个最根本的Jsona. 解析个别Json对象a_dict = {<!-- --> 'school': 'ABC primary school', 'location': 'London', 'ranking': 2}pd.json_normalize(a_dict)输入后果为:
b. 解析一个Json对象列表json_list = [ {<!-- -->'class': 'Year 1', 'student number': 20, 'room': 'Yellow'}, {<!-- -->'class': 'Year 2', 'student number': 25, 'room': 'Blue'}]pd.json_normalize(json_list)输入后果为:
2. 解析一个带有多层数据的Jsona. 解析一个有多层数据的Json对象json_obj = {<!-- --> 'school': 'ABC primary school', 'location': 'London', 'ranking': 2, 'info': {<!-- --> 'president': 'John Kasich', 'contacts': {<!-- --> 'email': {<!-- --> 'admission': 'admission@abc.com', 'general': 'info@abc.com' }, 'tel': '123456789', } }}pd.json_normalize(json_obj)输入后果为:
多层key之间应用点隔开,展现了所有的数据,这曾经解析了3层,上述写法和pd.json_normalize(json_obj, max_level=3)等价。
如果设置max_level=1,则输入后果为下图所示,contacts局部的数据会集成了一列
如果设置max_level=2,则输入后果为下图所示,contacts 下的email局部的数据会集成了一列
b. 解析一个有多层数据的Json对象列表json_list = [ {<!-- --> 'class': 'Year 1', 'student count': 20, 'room': 'Yellow', 'info': {<!-- --> 'teachers': {<!-- --> 'math': 'Rick Scott', 'physics': 'Elon Mask' } } }, {<!-- --> 'class': 'Year 2', 'student count': 25, 'room': 'Blue', 'info': {<!-- --> 'teachers': {<!-- --> 'math': 'Alan Turing', 'physics': 'Albert Einstein' } } }]pd.json_normalize(json_list)输入后果为:
若别离将max_level设置为2和3,则输入后果应别离是什么?请自行尝试~
3. 解析一个带有嵌套列表的Jsonjson_obj = {<!-- --> 'school': 'ABC primary school', 'location': 'London', 'ranking': 2, 'info': {<!-- --> 'president': 'John Kasich', 'contacts': {<!-- --> 'email': {<!-- --> 'admission': 'admission@abc.com', 'general': 'info@abc.com' }, 'tel': '123456789', } }, 'students': [ {<!-- -->'name': 'Tom'}, {<!-- -->'name': 'James'}, {<!-- -->'name': 'Jacqueline'} ],}pd.json_normalize(json_obj)此例中students键对应的值是一个列表,应用[]括起来。间接采纳上述的办法进行解析,则失去的后果如下:
students局部的数据并未被胜利解析,此时能够为record_path设置值即可,调用形式为pd.json_normalize(json_obj, record_path='students'),在此调用形式下,失去的后果只蕴含了name局部的数据。
若要减少其余字段的信息,则需为meta参数赋值,例如下述调用形式下,失去的后果如下:
pd.json_normalize(json_obj, record_path='students', meta=['school', 'location', ['info', 'contacts', 'tel'], ['info', 'contacts', 'email', 'general']])
4. 当Key不存在时如何疏忽零碎报错data = [ {<!-- --> 'class': 'Year 1', 'student count': 20, 'room': 'Yellow', 'info': {<!-- --> 'teachers': {<!-- --> 'math': 'Rick Scott', 'physics': 'Elon Mask', } }, 'students': [ {<!-- --> 'name': 'Tom', 'sex': 'M' }, {<!-- --> 'name': 'James', 'sex': 'M' }, ] }, {<!-- --> 'class': 'Year 2', 'student count': 25, 'room': 'Blue', 'info': {<!-- --> 'teachers': {<!-- --> # no math teacher 'physics': 'Albert Einstein' } }, 'students': [ {<!-- --> 'name': 'Tony', 'sex': 'M' }, {<!-- --> 'name': 'Jacqueline', 'sex': 'F' }, ] },]pd.json_normalize( data, record_path =['students'], meta=['class', 'room', ['info', 'teachers', 'math']])在class等于Year 2的Json对象中,teachers下的math键不存在,间接运行上述代码会报以下谬误,提醒math键并不总是存在,且给出了相应倡议:Try running with errors='ignore'。
增加errors条件后,从新运行得出的后果如下图所示,没有math键的局部应用NaN进行了填补。
pd.json_normalize( data, record_path =['students'], meta=['class', 'room', ['info', 'teachers', 'math']], errors='ignore')
5. 应用sep参数为嵌套Json的Key设置分隔符在2.a的案例中,能够留神到输入后果的具备多层key的数据列题目是采纳.对多层key进行分隔的,能够为sep赋值以更改分隔符。
json_obj = {<!-- --> 'school': 'ABC primary school', 'location': 'London', 'ranking': 2, 'info': {<!-- --> 'president': 'John Kasich', 'contacts': {<!-- --> 'email': {<!-- --> 'admission': 'admission@abc.com', 'general': 'info@abc.com' }, 'tel': '123456789', } }}pd.json_normalize(json_obj, sep='->')输入后果为:
6. 为嵌套列表数据和元数据增加前缀在3例的输入后果中,各列名均无前缀,例如name这一列不知是元数据解析失去的数据,还是通过student嵌套列表的的出的数据,因而为record_prefix和meta_prefix参数别离赋值,即可为输入后果增加相应前缀。
json_obj = {<!-- --> 'school': 'ABC primary school', 'location': 'London', 'ranking': 2, 'info': {<!-- --> 'president': 'John Kasich', 'contacts': {<!-- --> 'email': {<!-- --> 'admission': 'admission@abc.com', 'general': 'info@abc.com' }, 'tel': '123456789', } }, 'students': [ {<!-- -->'name': 'Tom'}, {<!-- -->'name': 'James'}, {<!-- -->'name': 'Jacqueline'} ],}pd.json_normalize(json_obj, record_path='students', meta=['school', 'location', ['info', 'contacts', 'tel'], ['info', 'contacts', 'email', 'general']], record_prefix='students->', meta_prefix='meta->', sep='->')本例中,为嵌套列表数据增加students->前缀,为元数据增加meta->前缀,将嵌套key之间的分隔符批改为->,输入后果为:
7. 通过URL获取Json数据并进行解析通过URL获取数据须要用到requests库,请自行装置相应库。
import requestsfrom pandas import json_normalize# 通过天气API,获取深圳近7天的天气url = 'https://tianqiapi.com/free/week'# 传入url,并设定好相应的paramsr = requests.get(url, params={<!-- -->"appid":"59257444", "appsecret":"uULlTGV9 ", 'city':'深圳'})# 将获取到的值转换为json对象result = r.json()df = json_normalize(result, meta=['city', 'cityid', 'update_time'], record_path=['data'])dfresult的后果如下所示,其中data为一个嵌套列表:
{<!-- -->'cityid': '101280601', 'city': '深圳', 'update_time': '2021-08-09 06:39:49', 'data': [{<!-- -->'date': '2021-08-09', 'wea': '中雨转雷阵雨', 'wea_img': 'yu', 'tem_day': '32', 'tem_night': '26', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-10', 'wea': '雷阵雨', 'wea_img': 'yu', 'tem_day': '32', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-11', 'wea': '雷阵雨', 'wea_img': 'yu', 'tem_day': '31', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-12', 'wea': '多云', 'wea_img': 'yun', 'tem_day': '33', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-13', 'wea': '多云', 'wea_img': 'yun', 'tem_day': '33', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-14', 'wea': '多云', 'wea_img': 'yun', 'tem_day': '32', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}, {<!-- -->'date': '2021-08-15', 'wea': '多云', 'wea_img': 'yun', 'tem_day': '32', 'tem_night': '27', 'win': '无继续风向', 'win_speed': '<3级'}]}解析后的输入后果为:
...