У меня проблема. У меня есть вложенный файл JSON
:
json_data = '''
{
"appVersion": "",
"device": {
"model": ""
},
"bef": {
"catalog": ""
},
"data": [
{
"timestamp": "",
"label": "",
"category": ""
}
]
}
Я хотел бы извлечь все данные, и если они вложены, я бы хотел, чтобы они были разделены знаком _
.
Я попытался нормализовать вложенный файл JSON. Для этого я использую json_normalise
.
К сожалению, желаемый результат — это не то, что я хочу и что мне нужно.
Более того, я хочу, чтобы вложенных значений могло быть любое количество, поэтому я попытался решить эту проблему с помощью цикла.
Как я могу получить желаемый результат?
import pandas as pd
import json
json_data = '''
{
"appVersion": "0.0.3",
"device": {
"model": "Lenovo"
},
"bef": {
"catalog": "Manual"
},
"data": [
{
"timestamp": "2024-04-24 12:08:02.415077",
"label": "zuf",
"category": "50"
}
]
}
'''
parsed_json = json.loads(json_data)
def extract_metadata(json_data):
metadata = {}
for key, value in json_data.items():
if isinstance(value, dict):
for k, v in value.items():
metadata[f'{key}_{k}'] = v
else:
metadata[key] = value
return metadata
meta_data = extract_metadata(parsed_json)
df_main = pd.json_normalize(parsed_json['data'], sep='_')
df_meta = pd.DataFrame([meta_data])
df = pd.concat([df_main, df_meta], axis=1)
print(df)
Что я имею
timestamp label category appVersion device_model \
0 2024-04-24 12:08:02.415077 zuf 50 0.0.3 Lenovo
bef_catalog data
0 Manual [{'timestamp': '2024-04-24 12:08:02.415077', '...
Что я хочу
appVersion device_model bef_catalog data_timestamp data_label data_category
0.0.3 Lenovo Manual 2024-04-24 12:08:02.415 zuf 50
@AbdulAzizBarkat спасибо за ваш комментарий. К сожалению, реализация не соответствует желаемому результату. Отображаются только три поля вывода.
import pandas as pd
import json
def flatten_json(json_obj, parent_key='', sep='_'):
items = {}
for k, v in json_obj.items():
new_key = parent_key + sep + k if parent_key else k
if isinstance(v, dict):
items.update(flatten_json(v, new_key, sep=sep))
elif isinstance(v, list):
for i, item in enumerate(v):
items.update(flatten_json(item, f"{new_key}{sep}{i}", sep=sep))
else:
items[new_key] = v
return items
#Your JSON data
json_data = '''
{
"appVersion": "0.0.3",
"device": {
"model": "Lenovo"
},
"bef": {
"catalog": "Manual"
},
"data": [
{
"timestamp": "2024-04-24 12:08:02.415",
"label": "zuf",
"category": 50
}
]
} '''
# Parse the JSON data
parsed_data = json.loads(json_data)
# Flatten the JSON data
flattened_data = flatten_json(parsed_data)
# Convert flattened data to DataFrame
df = pd.DataFrame(flattened_data, index=[0])
print(df)
Вы можете сначала сгладить свой словарь следующим образом:
def flatten_dict(d: dict, pre=''):
new_d = {}
for key, item in d.items():
if isinstance(item, dict):
new_d = {**new_d, **flatten_dict(item, pre=f'{pre}{key}_')}
elif isinstance(item, list):
for i, ele in enumerate(item):
if isinstance(ele, dict):
new_d = {**new_d, **flatten_dict(ele, pre=f'{pre}{key}_{i+1}_')}
else:
new_d[f'{pre}{key}_{i+1}'] = ele
else:
new_d[f'{pre}{key}'] = item
return new_d
В вашем коде вы пропустили тип list
. Я добавил перечислитель, поскольку в list
можно иметь несколько словарей. Если вы уверены, что в списке всегда максимум 1 элемент, вы можете удалить i
. Или включите проверку или что-то еще, чтобы проверить, имеет ли список длину 1.
Чтобы преобразовать его в панды:
pd.json_normalize(flatten_dict(parsed_json))
Вывод функции:
flatten_dict(parsed_json)
{'appVersion': '0.0.3',
'device_model': 'Lenovo',
'bef_catalog': 'Manual',
'data_1_timestamp': '2024-04-24 12:08:02.415077',
'data_1_label': 'zuf',
'data_1_category': '50'}
Проблема в том, что вы пытаетесь нормализовать поле данных, которое представляет собой список словарей, а затем объединить его с матаданными. Вместо этого выполните итерацию по списку данных и для каждого словаря в нем объедините метаданные и добавьте их в свой фрейм данных:
import pandas as pd
import json
json_data = {your_json_data}
parsed_json = json.loads(json_data)
def extract_metadata(json_data):
metadata = {}
for key, value in json_data.items():
if isinstance(value, dict):
for k, v in value.items():
metadata[f'{key}_{k}'] = v
elif key != 'data':
metadata[key] = value
return metadata
meta_data = extract_metadata(parsed_json)
df = pd.DataFrame()
for data in parsed_json['data']:
data.update(meta_data)
df = df.append(data, ignore_index=True)
print(df)
Отвечает ли это на ваш вопрос? Как сгладить многоуровневый/вложенный JSON?