Я получаю несколько JSON, которые мне нужно преобразовать и объединить, что я делаю с пандами, а затем мне также нужно сгенерировать JSON. Структура итогового JSON фиксирована. иногда некоторые поля в JSON отсутствуют (и это правильно), но мне приходится сохранять поля в объединенном объекте, что тоже работает нормально. Мне нужно преобразовать все значения NaN в None, чтобы впоследствии получить действительный json с нулевыми значениями, но после операции groupby он преобразует некоторые значения None обратно в NaN.
См. прикрепленный пример:
import pandas as pd
import json
dict1 = {
"items": [
{
"name": "Project1",
"projectId": "1",
},
{
"name": "Project2",
"projectId": "2",
},
{
"name": "Project3",
"projectId": "3",
}
]
}
dict2 = {
"items": [
{
"attr1": "ABC",
"attr2": "DEF1",
"attr3": "GHI1",
"projectId": "1",
"services":[
{
"sname": "Service1",
},
{
"sname": "Service2",
}
]
},
{
"attr1": "ABC",
"attr2": "DEF2",
"attr3": "GHI2",
"projectId": "2",
"services":[
{
"sname": "Service1",
},
{
"sname": "Service2",
}
]
}
]
}
dict_head = {
"id":"some-guid",
"name":"some name",
"content" :[
]
}
df1 = pd.DataFrame(dict1["items"])
# df2 = pd.DataFrame(dict2["items"])
df2 = pd.json_normalize(
data = dict2['items'],
record_path = ['services'],
meta = [
'projectId',
'attr1',
'attr2',
'attr3'
]
)
df_joined = df1.set_index("projectId").join(df2.set_index("projectId"))
print("df_joined_1")
print(df_joined)
#convert all NaN vales to None whichs works well
df_joined= df_joined.where(pd.notnull(df_joined), None)
print("df_joined_2")
print(df_joined)
df_grouped = df_joined.groupby(['projectId','name','attr1','attr2','attr3'], dropna=False)['sname'].apply(list).reset_index().to_dict(orient='records')
#suddenly the None values of the grouped fields are conveted back to NaN???
print("df_grouped:")
print(df_grouped)
df_grouped = [{'type': 'Project', 'id': d['projectId'], 'data': d} for d in df_grouped.to_dict(orient='records')]
dict_head["content"] = df_grouped
print("dict_head:")
print(dict_head)
print("dict_head as json:")
print(json.dumps(dict_head, indent=3))
выходные данные проекта 3, где вы видите как NaN, так и ноль, я ожидаю, что все NaN будут нулевыми значениями.
{
"type": "Project",
"id": "3",
"data": {
"projectId": "3",
"name": "Project3",
"attr1": NaN,
"attr2": NaN,
"attr3": NaN,
"sname": [
null
]
}
}
Вам не нужно явно конвертировать NaN
в None
или конвертировать фрейм данных в dict
. Панды сделают это за вас, если вы воспользуетесь pandas.to_json
.
Вы можете использовать это для content
, а затем снова загрузить преобразованный json как list
, чтобы поместить его в нужную структуру:
df_joined = df1.set_index("projectId").join(df2.set_index("projectId"))
json_str = (
df_joined.groupby(["projectId", "name", "attr1", "attr2", "attr3"], dropna=False)[
"sname"
]
.apply(list)
.reset_index()
.to_json(orient = "records")
)
json_list = json.loads(json_str)
json_content = [{"type": "Project", "id": d["projectId"], "data": d} for d in json_list]
dict_head["content"] = json_content
json.dumps(dict_head, indent=3)
{
"id": "some-guid",
"name": "some name",
"content": [
{
"type": "Project",
"id": "1",
"data": {
"projectId": "1",
"name": "Project1",
"attr1": "ABC",
"attr2": "DEF1",
"attr3": "GHI1",
"sname": [
"Service1",
"Service2"
]
}
},
{
"type": "Project",
"id": "2",
"data": {
"projectId": "2",
"name": "Project2",
"attr1": "ABC",
"attr2": "DEF2",
"attr3": "GHI2",
"sname": [
"Service1",
"Service2"
]
}
},
{
"type": "Project",
"id": "3",
"data": {
"projectId": "3",
"name": "Project3",
"attr1": null,
"attr2": null,
"attr3": null,
"sname": [
null
]
}
}
]
}
ах, ладно, я забыл упомянуть одну вещь: я конвертирую в to_dict, потому что потом мне нужно сделать следующее: я, конечно, могу затем снова привести список обратно в DataFrame, чтобы использовать to_json, но, может быть, есть лучший способ?
@Fobber Для этой новой структуры вам понадобится больше шагов. Я обновил ответ соответственно.
спасибо @e-motta, все работает. но я изменил код вашего первого решения, поэтому мне нужно использовать только функцию pandas.to_json() при преобразовании dict в json, предварительно приведя его к DataFrame, потому что это немного быстрее, чем другое решение.
мне снова: D пришлось снова перейти на ваше решение, потому что другой создает json, окруженный [ ], не знаю, откуда он взялся. еще раз спасибо
забыл упомянуть операцию
df_grouped = [{'type': 'Project', 'id': d['projectId'], 'data': d} for d in df_grouped.to_dict(orient='records')]
добавил в свой вопрос