Как распарсить колонку json в pandas?
В датафрейме есть колонка со строками вида: {\'name\': {\'type\': \'STRING\', \'value\': \'test\'}, \'company\': {\'type\': \'STRING\', \'value\': \'ООО "Рога копыта"\'}, \'role\': {\'type\': \'STRING\', \'value\': \'пользователь\'}}
Пытаюсь распарсить на отдельные колонки, каждый кастомный параметр, взяв название колонки кастомного параметра и заполнив его значением в value.
Мой код:
temp_table = pd.json_normalize(data.custom)
list_col = [x for x in temp_table.columns if x.split('.')[1] == 'type']
temp_table = temp_table.drop(columns=list_col)
temp_table.columns = [x.split('.')[0] for x in temp_table.columns]
data = data[['col1', 'col2']].join(temp_table)
Проблема, что при pd.json_normalize(data.custom)
у меня возвращается пустая таблица. Мои предположения были, что проблема была в одинарных кавычках, я попробовала их заменить:
data.custom=data.custom.apply(lambda x: x.replace("'", '"'))
data.custom=data.custom.str.replace('"', '\\\"', regex=True)
не помогло. И пыталась привести строки в соответствие так:
data.custom=data.custom.apply(lambda x: json.loads(json.dumps(x)))
тоже не помогло. Теперь полагаю, что я не правильно установила причину. Возможно проблема в целом в моем коде.
Ответы (2 шт):
import pandas as pd
import json
your_dict = {'name': {'type': 'STRING', 'value': 'test'},
'company': {'type': 'STRING', 'value': 'ООО "Рога копыта"'},
'role': {'type': 'STRING', 'value': 'пользователь'}}
#Словарь в json
your_json_string=json.dumps(your_dict)
#JSON d JSON объект
data = json.loads(your_json_string)
#Датафрейм
df = pd.DataFrame(data)
print(df)
name company role
type STRING STRING STRING
value test ООО "Рога копыта" пользователь
Комментарии в коде
import ast # импортируем библиотеку ast для безопасного преобразования текста в словарь
df = pd.DataFrame({'Код': [1001, 1003, 1005],
'custom': ["""{'name': {'type': 'STRING', 'value': 'test'}, 'company': {'type': 'STRING', 'value': 'ООО "Рога копыта"'}, 'role': {'type': 'STRING', 'value': 'пользователь'}}""",
"""{'name': {'type': 'STRING', 'value': 'Вася'}, 'company': {'type': 'STRING', 'value': 'ООО "Ромашка"'}, 'role': {'type': 'STRING', 'value': 'админ'}}""",
"""{'name': {'type': 'STRING', 'value': 'Петя'}, 'company': {'type': 'STRING', 'value': 'ООО "Ронин"'}, 'role': {'type': 'STRING', 'value': 'продавец'}}"""]})
df.custom = df.custom.transform(ast.literal_eval) # преобразуем текст в словари в каждой ячейке столбца custom
fields = list(set(df.custom.transform(list).sum())) # из этого же столбца вытаскиваем множество ключей - они станут названиями столбцов
df[fields] = df['custom'].apply(lambda x: pd.Series({k: x[k]['value'] for k in x})) # разбираем словари на столбцы
df = df.drop(columns='custom') # удаляем исходный столбец custom, если он уже не нужен
print(df)
Код name company role
0 1001 test ООО "Рога копыта" пользователь
1 1003 Вася ООО "Ромашка" админ
2 1005 Петя ООО "Ронин" продавец
Другой подход - сделать список словарей, затем за 1 операцию преобразовать во фрейм. Протестил на 810 к строчек, отработало за 33 секунды.
import ast # импортируем библиотеку ast для безопасного преобразования текста в словарь
import time
start = time.time()
mul = 270_000 #000
df = pd.DataFrame({'Код': [1001, 1003, 1005] * mul,
'custom': ["""{'name': {'type': 'STRING', 'value': 'test'}, 'company': {'type': 'STRING', 'value': 'ООО "Рога копыта"'}, 'role': {'type': 'STRING', 'value': 'пользователь'}}""",
"""{'name1': {'type': 'STRING', 'value': 'Вася'}, 'company1': {'type': 'STRING', 'value': 'ООО "Ромашка"'}, 'role1': {'type': 'STRING', 'value': 'админ'}}""",
"""{'name2': {'type': 'STRING', 'value': 'Петя'}, 'company2': {'type': 'STRING', 'value': 'ООО "Ронин"'}, 'role2': {'type': 'STRING', 'value': 'продавец'}}"""] * mul})
lst = []
dicts = df.custom.transform(ast.literal_eval) # преобразуем текст в словари в каждой ячейке столбца custom
dicts.apply(lambda x: lst.append({k: x[k]['value'] for k in x}))
df = pd.DataFrame(lst)
print(df.head())
print((time.time()-start), 'сек.')
name company role name1 company1 role1 name2 company2 role2
0 test ООО "Рога копыта" пользователь NaN NaN NaN NaN NaN NaN
1 NaN NaN NaN Вася ООО "Ромашка" админ NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN Петя ООО "Ронин" продавец
3 test ООО "Рога копыта" пользователь NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN Вася ООО "Ромашка" админ NaN NaN NaN
32.78659248352051 сек.
То же одной строкой (цепочкой методов):
df = pd.DataFrame(df.custom.transform(ast.literal_eval).apply(lambda x: {k: x[k]['value'] for k in x}).to_list()) # преобразуем текст в словари в каждой ячейке столбца custom, переводим в список словарей и создаем новый фрейм