Удалить вложенные JSON из DataFrame без создания новых строк или дублирования данных - PullRequest
0 голосов
/ 01 апреля 2020

ОБЗОР

С помощью pandas.json_normalize мне удалось нормализовать JSON данных, которые были выведены из BigQuery с несколькими вложенными объектами, в кадр данных. CSV-представление ниже. Вы заметите на таких вещах, как «устройство», оно вспыхнуло так, как должно. В других случаях, таких как столбец и event_params, это не так. Я поиграл и смог расширить этот объект, но он привнесет новые роли, к счастью, мне нужен только один ключ / значение в зависимости от значения event_name. В этом примере я хочу извлечь session_user_id и нормализовать его в похожую широкую колонку.

CSV DATA

event_date,event_timestamp,event_name,event_params,device.operating_system  device.operating_system_version
20200105,69996099900,session_start,[{'key': 'ga_session_number', 'value': {'string_value': None, 'int_value': '3', 'float_value': None, 'double_value': None}}, {'key': 'session_engaged', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'engaged_session_event', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'session_id', 'value': {'string_value': None, 'int_value': '123456789', 'float_value': None, 'double_value': None}}, {'key': 'firebase_event_origin', 'value': {'string_value': 'auto', 'int_value': None, 'float_value': None, 'double_value': None}}],IOS,9.3.5

QUESTION

Возможно, я просто в замешательстве, но есть ли простой способ выделить один (или проще, все ключи) со связанными значениями в дополнительные столбцы?

Например, новые столбцы будут выглядеть так:

(Честно говоря, наименование ключа / значения не так уж и важно, если рассматривать его в виде плоского файла CSV)

event_params.1.key = session_engaged
event_params.1.string_value = None
event_params.1.int_value = 1
[...]

event_params.2.key = session_id
event_params.2.string_value = None
event_params.2.int_value = 123456789
[...]

1 Ответ

0 голосов
/ 02 апреля 2020

Этот ответ, хотя он и не очень элегантный и, вероятно, требует немного работы, чтобы получить именно то, что вам нужно, - разумное начало.

Данные настройки

Я имею взял данные вашего примера и слегка изменил формат, чтобы загрузить его в dataframe.

columns = 'event_date event_timestamp event_name event_params device.operating_system device.operating_system_version'.split()
data = [
        20200105,
        69996099900,
        'session_start',
        [{'key': 'ga_session_number', 'value': {'string_value': None, 'int_value': '3', 'float_value': None, 'double_value': None}}, {'key': 'session_engaged', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'engaged_session_event', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'session_id', 'value': {'string_value': None, 'int_value': '123456789', 'float_value': None, 'double_value': None}}, {'key': 'firebase_event_origin', 'value': {'string_value': 'auto', 'int_value': None, 'float_value': None, 'double_value': None}}],
        'IOS',
        '9.3.5',
        ]

df = pd.DataFrame([data], columns=columns)

Исходные данные:

   event_date  event_timestamp     event_name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            event_params device.operating_system device.operating_system_version
0    20200105      69996099900  session_start  [{'key': 'ga_session_number', 'value': {'string_value': None, 'int_value': '3', 'float_value': None, 'double_value': None}}, {'key': 'session_engaged', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'engaged_session_event', 'value': {'string_value': None, 'int_value': '1', 'float_value': None, 'double_value': None}}, {'key': 'session_id', 'value': {'string_value': None, 'int_value': '123456789', 'float_value': None, 'double_value': None}}, {'key': 'firebase_event_origin', 'value': {'string_value': 'auto', 'int_value': None, 'float_value': None, 'double_value': None}}]                     IOS                           9.3.5

Решение

new_df = df.explode('event_params').event_params.apply(pd.Series).value.apply(pd.Series)
df = pd.concat([df.drop('event_params', axis=1), new_df], axis=1)

Вывод:

   event_date  event_timestamp     event_name device.operating_system device.operating_system_version string_value  int_value float_value double_value
0    20200105      69996099900  session_start                     IOS                           9.3.5         None          3        None         None
0    20200105      69996099900  session_start                     IOS                           9.3.5         None          1        None         None
0    20200105      69996099900  session_start                     IOS                           9.3.5         None          1        None         None
0    20200105      69996099900  session_start                     IOS                           9.3.5         None  123456789        None         None
0    20200105      69996099900  session_start                     IOS                           9.3.5         auto       None        None         None

Пояснение

Я разбью описание первой строки на несколько шагов:

  1. Использование explode просто для доступа к внутренней части списка в event_params (вы можете apply лямбда-функцию, если хотите).
  2. Сначала используйте apply.(pd.Series), чтобы развернуть JSON , см. здесь для больше информации .
  3. Снова используйте apply.(pd.Series), чтобы развернуть столбец values.

Конечно, вторая строка просто объединяет два кадра данных вместе с event_params исключено из исходных данных.

...