我有一个json数据(来自mongodb),其中包含数千条记录(即json对象的数组/列表),每个对象的结构如下所示:
{
"id":1,
"first_name":"Mead",
"last_name":"Lantaph",
"email":"mlantaph0@opensource.org",
"gender":"Male",
"ip_address":"231.126.209.31",
"nested_array_to_expand":[
{
"property":"Quaxo",
"json_obj":{
"prop1":"Chevrolet",
"prop2":"Mercy Streets"
}
},
{
"property":"Blogpad",
"json_obj":{
"prop1":"Hyundai",
"prop2":"Flashback"
}
},
{
"property":"Yabox",
"json_obj":{
"prop1":"Nissan",
"prop2":"Welcome Mr. Marshall (Bienvenido Mister Marshall)"
}
}
]
}
当加载到数据帧中时,"nested_array_to_expand“是一个包含json的字符串(我确实在加载过程中使用了"json_normalize”)。预期的结果是获得一个包含3行(给定上面的示例)和嵌套对象的新列的数据帧,如下所示:
index email first_name gender id ip_address last_name \
0 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
1 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
2 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
test.name test.obj.ahah test.obj.buzz
0 Quaxo Mercy Streets Chevrolet
1 Blogpad Flashback Hyundai
2 Yabox Welcome Mr. Marshall (Bienvenido Mister Marshall) Nissan
我可以用下面的函数得到这个结果,但它非常慢( 1k个记录大约2秒),所以我想要么改进现有的代码,要么找到一个完全不同的方法来获得这个结果。
def expand_field(field, df, parent_id='id'):
all_sub = pd.DataFrame()
# we need an id per row to be able to merge back dataframes
# if no id, then we will create one based on index of rows
if parent_id not in df:
df[parent_id] = df.index
# go through all rows and create a new dataframe with values
for i, row in df.iterrows():
try:
sub = json_normalize(df[field].values[i])
sub = sub.add_prefix(field + '.')
sub['parent_id'] = row[parent_id]
all_sub = all_sub.append(sub)
except:
print('crash')
pass
df = pd.merge(df, all_sub, left_on=parent_id, right_on='parent_id', how='left')
#remove old columns
del df["parent_id"]
del df[field]
#return expanded dataframe
return df
非常感谢你的帮助。
用于回答评论====的=====编辑
从mongodb加载的数据是一个object数组。我用下面的代码加载它:
data = json.loads(my_json_string)
df = json_normalize(data)
输出给我一个df"nested_array_to_expand“作为dtype对象(字符串)数据帧
0 [{'property': 'Quaxo', 'json_obj': {'prop1': '...
Name: nested_array_to_expand, dtype: object
发布于 2017-12-12 05:07:19
我提出了一个有趣的答案,我认为使用pandas.json_normalize
。
我用它来扩展嵌套的json
--也许还有更好的方法,但是您一定要考虑使用这个特性。然后,您只需根据需要对列进行重命名。
import io
from pandas import json_normalize
# Loading the json string into a structure
json_dict = json.load(io.StringIO(json_str))
df = pd.concat([pd.DataFrame(json_dict),
json_normalize(json_dict['nested_array_to_expand'])],
axis=1).drop('nested_array_to_expand', 1)
发布于 2018-09-25 12:55:28
下面的代码就是您想要的。您可以使用python的内置列表函数来展开嵌套列表,并将其作为新的dataframe进行传递。pd.DataFrame(list(json_dict['nested_col']))
您可能需要进行多次迭代,这取决于数据的嵌套程度。
from pandas.io.json import json_normalize
df= pd.concat([pd.DataFrame(json_dict), pd.DataFrame(list(json_dict['nested_array_to_expand']))], axis=1).drop('nested_array_to_expand', 1)
发布于 2020-12-08 09:24:20
import pandas as pd
import json
data = '''
[
{
"id":1,
"first_name":"Mead",
"last_name":"Lantaph",
"email":"mlantaph0@opensource.org",
"gender":"Male",
"ip_address":"231.126.209.31",
"nested_array_to_expand":[
{
"property":"Quaxo",
"json_obj":{
"prop1":"Chevrolet",
"prop2":"Mercy Streets"
}
},
{
"property":"Blogpad",
"json_obj":{
"prop1":"Hyundai",
"prop2":"Flashback"
}
},
{
"property":"Yabox",
"json_obj":{
"prop1":"Nissan",
"prop2":"Welcome Mr. Marshall (Bienvenido Mister Marshall)"
}
}
]
}
]
'''
data = json.loads(data)
result = pd.json_normalize(data, "nested_array_to_expand",
['email', 'first_name', 'gender', 'id', 'ip_address', 'last_name'])
结果
property json_obj.prop1 json_obj.prop2 \
0 Quaxo Chevrolet Mercy Streets
1 Blogpad Hyundai Flashback
2 Yabox Nissan Welcome Mr. Marshall (Bienvenido Mister Marshall)
email first_name gender id ip_address last_name
0 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
1 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
2 mlantaph0@opensource.org Mead Male 1 231.126.209.31 Lantaph
有关json_normalize
的更多信息,请访问:https://pandas.pydata.org/docs/reference/api/pandas.json_normalize.html
https://stackoverflow.com/questions/47765243
复制