首发于公众号:Python数据迷信作者:东哥腾飞
调用API
和文档数据库会返回嵌套的JSON
对象,当咱们应用Python
尝试将嵌套构造中的键转换为列时,数据加载到pandas
中往往会失去如下后果:
df = pd.DataFrame.from_records(results [“ issues”],columns = [“ key”,“ fields”])
阐明:这里results是一个大的字典,issues是results其中的一个键,issues的值为一个嵌套JSON对象字典的列表,前面会看到JSON嵌套构造。
问题在于API返回了嵌套的JSON
构造,而咱们关怀的键在对象中确处于不同级别。
嵌套的JSON
构造张成这样的。
而咱们想要的是上面这样的。
上面以一个API返回的数据为例,API通常蕴含无关字段的元数据。假如上面这些是咱们想要的字段。
- key:JSON密钥,在第一级的地位。
- summary:第二级的“字段”对象。
- status name:第三级地位。
- statusCategory name:位于第4个嵌套级别。
如上,咱们抉择要提取的字段在issues列表内的JSON
构造中别离处于4个不同的嵌套级别,一环扣一环。
{ "expand": "schema,names", "issues": [ { "fields": { "issuetype": { "avatarId": 10300, "description": "", "id": "10005", "name": "New Feature", "subtask": False }, "status": { "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.", "id": "5", "name": "Resolved", "statusCategory": { "colorName": "green", "id": 3, "key": "done", "name": "Done", } }, "summary": "Recovered data collection Defraglar $MFT problem" }, "id": "11861", "key": "CAE-160", }, { "fields": { ... more issues], "maxResults": 5, "startAt": 0, "total": 160}
一个不太好的解决方案
一种抉择是间接撸码,写一个查找特定字段的函数,但问题是必须对每个嵌套字段调用此函数,而后再调用.apply
到DataFrame
中的新列。
为获取咱们想要的几个字段,首先咱们提取fields键内的对象至列:
df = ( df["fields"] .apply(pd.Series) .merge(df, left_index=True, right_index = True))
从上表看出,只有summary是可用的,issuetype、status等依然埋在嵌套对象中。
上面是提取issuetype中的name的一种办法。
# 提取issue type的name到一个新列叫"issue_type"df_issue_type = ( df["issuetype"] .apply(pd.Series) .rename(columns={"name": "issue_type_name"})["issue_type_name"])df = df.assign(issue_type_name = df_issue_type)
像下面这样,如果嵌套层级特地多,就须要本人手撸一个递归来实现了,因为每层嵌套都须要调用一个像下面解析并增加到新列的办法。
对于编程基础薄弱的敌人,手撸一个其实还挺麻烦的,尤其是对于数据分析师,焦急想用数据的时候,心愿能够疾速拿到结构化的数据进行剖析。
上面东哥分享一个pandas
的内置解决方案。
内置的解决方案
pandas
中有一个牛逼的内置性能叫 .json_normalize
。
pandas
的文档中提到:将半结构化JSON
数据规范化为立体表。
后面计划的所有代码,用这个内置性能仅须要3行就可搞定。步骤很简略,懂了上面几个用法即可。
确定咱们要想的字段,应用 . 符号连贯嵌套对象。
将想要解决的嵌套列表(这里是results["issues"]
)作为参数放进 .json_normalize
中。
过滤咱们定义的FIELDS列表。
FIELDS = ["key", "fields.summary", "fields.issuetype.name", "fields.status.name", "fields.status.statusCategory.name"]df = pd.json_normalize(results["issues"])df[FIELDS]
没错,就这么简略。
其它操作
记录门路
除了像下面那样传递results["issues"]
列表之外,咱们还应用record_path
参数在JSON
对象中指定列表的门路。
# 应用门路而不是间接用results["issues"]pd.json_normalize(results, record_path="issues")[FIELDS]
自定义分隔符
还能够应用sep参数自定义嵌套构造连贯的分隔符,比方上面将默认的“.”替换“-”。
### 用 "-" 替换默认的 "."FIELDS = ["key", "fields-summary", "fields-issuetype-name", "fields-status-name", "fields-status-statusCategory-name"]pd.json_normalize(results["issues"], sep = "-")[FIELDS]
管制递归
如果不想递归到每个子对象,能够应用max_level
参数管制深度。在这种状况下,因为statusCategory.name
字段位于JSON
对象的第4级,因而不会蕴含在后果DataFrame
中。
# 只深刻到嵌套第二级pd.json_normalize(results, record_path="issues", max_level = 2)
上面是.json_normalize
的pandas
官网文档阐明,如有不明确可自行学习,本次东哥就介绍到这里。
pandas官网文档:https://pandas.pydata.org/pan...
原创不易,感觉不错点个赞。
欢送关注我的集体公众号:Python数据迷信
数据迷信学习网站:datadeepin