如何更优雅高效地实现字符串JSON列的DataFrame转换?
优化JSON字符串列解析为结构化DataFrame的方案
问题背景
原始DataFrame的info列存储JSON格式字符串:
info {"any_name":{"value":["5"], "ref":"any text"}, "another_name":{"value":["2"], "ref":"any text"} {"any_name":{"value":["1"], "ref":"any text"}, "another_name":{"value":["12"], "ref":"any text"}
该列数据类型为str,目标是转换为以下结构化DataFrame:
any_name another_name 5 2 1 12
原实现方案如下(可运行但效率和安全性不足):
A=list(df['answers']) J=[] for i in range(0,len(A)): D=eval(A[i]) foo = {k: v['value'] for k, v in D.items() if k in list_to_filter_columns} J.append(foo) out=pd.DataFrame(J) # 转换数值类型 outt = outt.apply(lambda x: x.str[0]) outt = outt.apply(pd.to_numeric) outt.head(2)
更高效优雅的实现方案
核心优化点
- 替换
eval为json.loads:消除安全风险,提升解析效率 - 用
pd.json_normalize替代手动循环:利用pandas向量式操作简化代码,提升性能
完整优化代码
import json import pandas as pd # 链式调用完成解析、过滤、格式转换 result = df['info']\ .apply(json.loads)\ .pipe(pd.json_normalize)\ .filter(regex=r'^({})\.value'.format('|'.join(list_to_filter_columns)))\ .rename(columns=lambda col: col.split('.')[0])\ .applymap(lambda x: pd.to_numeric(x[0])) result.head()
代码分步说明
- 解析JSON字符串:
df['info'].apply(json.loads)将每个JSON字符串转为Python字典,相比eval,json.loads专门处理JSON格式,无代码执行风险,速度更快。 - 展开嵌套结构:
.pipe(pd.json_normalize)把嵌套的字典结构展开为扁平DataFrame,列名自动生成为key.value、key.ref格式。 - 过滤目标字段:
.filter(regex=r'^({})\.value'.format('|'.join(list_to_filter_columns)))通过正则匹配,只保留目标列的value字段,精准筛选需要的数据。 - 重命名列名:
.rename(columns=lambda col: col.split('.')[0])将列名从any_name.value简化为any_name,符合目标格式。 - 转换数值类型:
.applymap(lambda x: pd.to_numeric(x[0]))批量取出每个value列表的第一个元素,并转为数值型,applymap比逐列apply的执行效率更高。
额外优化建议
如果你的list_to_filter_columns是固定的(比如["any_name", "another_name"]),可以直接写死字段名,避免字符串拼接的开销:
# 固定列时的简化写法 result = df['info']\ .apply(json.loads)\ .pipe(pd.json_normalize)\ .filter(['any_name.value', 'another_name.value'])\ .rename(columns=lambda col: col.split('.')[0])\ .applymap(lambda x: pd.to_numeric(x[0]))
内容的提问来源于stack exchange,提问作者math_guy_shy
相关产品推荐
相关产品推荐

