Моя конечная цель состоит в том, чтобы сгладить ключ в списке диктов в кадре данных. Значение ключа также является списком диктов, и этот список может быть пустым для любой данной записи в списке верхнего уровня. Я пытаюсь сделать это быстро, поэтому пытаюсь использовать векторизованные операции в pandas, включая json_normalize
(что, я полагаю, лучше, чем al oop).
В результирующем фрейме данных я хочу сохранить некоторые столбцы верхнего уровня, сглаживая все ключи в списке вложенных диктов. Я также хочу, чтобы операция завершилась неудачей, если в любом вложенном списке есть какой-то элемент dict, в котором нет всех указанных мной ключей. Но я не хочу, чтобы операция не выполнялась, если ключ существует, но имеет значение None
. (Вот почему я не могу просто проверить NaN
после нормализации - None
преобразуется в NaN
для типов с плавающей запятой в json_normalize
, поскольку он не предоставляет аргумент dtype
, поэтому я бы не стал Не знаю, было ли это NaN
, потому что ключ не существовал или потому что он действительно существовал, но был None
).
Например, я попытался сделать что-то вроде этого:
data = [
{
'id': 1,
'topfield1': "1-1",
'topfield2': "1-2",
'topfield3': "1-3",
'topfield4': "1-4",
'payments': [
{'id': 1, 'amt': 2.0, 'not_required': 'something'},
{'id': 2, 'amt': 4.0}
]
},
{
'id': 2,
'topfield1': "2-1",
'topfield2': "2-2",
'topfield3': "2-3",
'topfield4': "2-4",
'payments': [
{'id': 1}
]
},
{
'id': 3,
'topfield1': "3-1",
'topfield2': "3-2",
'topfield3': "3-3",
'topfield4': "3-4",
'payments': []
}
]
# now flatten into one row for each item in each record's 'payments' key, keeping top-level 'id', 'topfield1', 'topfield4' and raising error if payments.id or payments.amt does not exist in a payment
#ideally, it would work like this:
# i want this to raise an error since data[1]['payments'][0] does not have key 'amt'. apparently that's not how json_normalize works -- it just throws a TypeError because apparently meta columns can't be from the record_path
pandas.io.json.json_normalize(data, record_path='payments', meta=['id', 'topfield4', 'topfield1', ['payments', 'id'], ['payments', 'amt']])
'''expected output
KeyError: 'payments.amt' or something like that
'''
'''actual output
TypeError: list indices must be integers or slices, not str
'''
data[1]['payments'][0]['amt'] = None
# now every 'payment' has 'id' and 'amt' keys so should succeed. but this still throws TypeError.
pandas.io.json.json_normalize(data, record_path='payments', meta=['id', 'topfield4', 'topfield1', ['payments', 'id'], ['payments', 'amt']])
'''expected output
id topfield4 topfield1 payments.id payments.amt payments.not_required
1 1-4 1-1 1 2.0 something
1 1-4 1-1 2 4.0 NaN
2 2-4 2-1 1 NaN NaN
'''
'''actual output
TypeError: list indices must be integers or slices, not str
'''
Но это не работает. Всякий раз, когда я использую поля из payments
объектов - то есть ключей объектов в списке record_path
- в качестве полей в meta
arg, я получаю TypeError: list indices must be integers or slices, not str
.
Это также выглядит как json_normalize
не достаточно умен, чтобы фактически следовать тем путям, которые вы указали в аргументе meta
, поскольку: (хотя я думаю, я мог бы просто переименовать соответствующие столбцы верхнего уровня, чтобы избежать)
# data as from above
pandas.io.json.json_normalize(data, record_path='payments', meta=['id'])
# fails with ValueError: Conflicting metadata name id, need distinguishing prefix`
# (shouldn't it know `id` is top-level since it's not a nested path?)
Есть ли векторизованный / быстрый способ выполнения sh того, что я хочу сделать?
Спасибо за любую помощь.
РЕДАКТИРОВАТЬ 1: может быть много полей верхнего уровня, и я хочу их подмножество в окончательном фрейме данных. РЕДАКТИРОВАТЬ 2: Добавлено больше полей, чтобы сделать минимально воспроизводимый пример.