Как сопоставить все ключи вложенного словаря с фреймом данных, используя отдельный столбец для каждого ключа в python

Я новичок в python, и я пытаюсь добиться следующего.

У меня есть этот словарь:

cust_DB = {'cust_ID': {'NAME': 'name', 'ADDRESS': 'address', 'PHONES': {'HOME_PHONE': 'home#', 'WORK_PHONE': 'work#', 'MOBILE_PHONE': 'mobile#'}, 'EMAILS': {'HOME_EMAIL': 'email@home', 'WORK_EMAIL': 'email@work'}

Я хотел бы преобразовать и поместить этот словарь в фрейм данных pandas df со следующими столбцами df и соответствующими записями:

'ID'|'NAME'|'ADDRESS'|'HOME_PHONE'|'WORK_PHONE'|'MOBILE_PHONE'|'HOME_EMAIL'|'WORK_EMAIL'

Если я использую pandas.DataFrame.from_dict(), вложенные номера телефонов и электронные письма группируются в один столбец каждый. Есть ли быстрый способ заполнить этот фрейм данных?

Спасибо!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
554
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Давайте попробуем эту пользовательскую функцию flatten:

def flatten(d):
    ret = dict()
    for k, v in d.items():
        if isinstance(v, dict):
            sub = flatten(v)
            for kk, vv in sub.items():
                ret[kk] = vv
        else: ret[k] = v
    return ret

out = pd.DataFrame({k:flatten(v) for k, v in cust_DB.items()})
out = out.T.rename_axis('ID').reset_index()

Выход:

    ID       ADDRESS    HOME_EMAIL    HOME_PHONE    MOBILE_PHONE    NAME    WORK_EMAIL    WORK_PHONE
--  -------  ---------  ------------  ------------  --------------  ------  ------------  ------------
 0  cust_ID  address    email@home    home#         mobile#         name    email@work    work#

Мой ответ ниже очень длинный.

Тем не менее, я верю в следующую старую поговорку:

Если дать человеку рыбу, он будет сыт один день.
Если научить человека ловить рыбу, он будет сыт всю жизнь.

У вас есть словарь словарей.
Я рекомендую вам визуализировать вложенный словарь в виде дерева:

"Лист" - это просто узел (узлы - круг/точка) в дереве, у которого нет дочерних элементов. «Листья» подобны людям-холостякам или старым девам: у них нет детей.

Похоже, вы хотите одну из следующих двух вещей. Я не уверен, какой ....

  • вы хотите использовать только листья дерева в качестве заголовков столбцов таблицы.
  • вы хотите извлечь родителей листовых узлов в дереве. Родители листьев станут заголовками столбцов для таблицы.

Это часто называют «сплющиванием» дерева.

cust_DB = {'cust_ID': {'NAME': 'name', 'ADDRESS': 'address', 'PHONES': {'HOME_PHONE': 'home#', 'WORK_PHONE': 'work#', 'MOBILE_PHONE': 'mobile#'}, 'EMAILS': {'HOME_EMAIL': 'email@home', 'WORK_EMAIL': 'email@work'}}}

def flatten(parent):
    """
    [* crickets chirping for lack of code-comments* ]
    """
    if not hasattr(parent, '__iter__'):
        return parent
    leaves = list()
    root_type = type(parent)
    for child_key in iter(parent):
        child = parent[child_key]
        if type(child) == type(parent):
            subleaves = flatten(child)
            leaves.extend(subleaves)
        else:
            leaves.append(child)
    return leaves

leaves = flatten(cust_DB)

result = "\n".join(map(str, iter(leaves)))
print(result)

Я вижу это:

  • Листья вашего дерева могут быть реальными данными (настоящими телефонными номерами).
  • родители конечных узлов — это заголовки столбцов таблицы («домашний телефон», «рабочий телефон» и т. д.).

Я рекомендую следующее решение:

  1. Погуглите "дерево словаря Python Flatten". Функция flatten, которую я дал выше, работает, но уродлива. Некоторые другие люди написали более элегантные функции сглаживания.
  2. Измените чью-то функцию flatten, чтобы получить родителей листовых узлов вместо листьев.

Если вы никогда не знали о поиске в глубину или поиске в ширину, я рекомендую посмотреть видео на YouTube по этим темам.

ПРЕДУПРЕЖДЕНИЕ/ВНИМАНИЕ:

Возникает одна проблема:

итераторы списков python возвращают значения, а не ключ. итераторы словарей Python возвращают ключи, а не значения.

Python — это то, что мне нравится называть языком «два шага вперед, один шаг назад». То есть Python в чем-то лучше старых языков (таких как C), а в чем-то хуже.

Если бы Python был хорошо спроектирован, все встроенные контейнеры (list, dict и т. д.) различали бы итераторы ключей и итераторы значений.

lyst = ["Spam", "Toast", "Eggs"]
# The keys (inputs) of lyst  are:
#    0, 1, 2
# The values (outputs) of `lyst` are:
#     Spam", "Toast", and "Eggs"

dyct = {0: "Spam", 1:"Toast", 2:"Eggs"}
# The keys (inputs) of dyct  are:
#    0, 1, 2
# The values (outputs) of `dyct` are:
#     Spam", "Toast", and "Eggs"

print("LIST STUFF IS BELOW")
for element in lyst:
    print(element)

print(end = "\n")

print("DICT STUFF IS BELOW")
for element in dyct:
    print(element)

Вы могли бы подумать, что вывод будет одинаковым как для списков, так и для словарей, но вывод отличается.

LIST STUFF IS BELOW
Spam
Toast
Eggs
    
DICT STUFF IS BELOW
0
1
2

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

#####################################
# BEGIN CODE FOR LISTS
#####################################
for child in parent:
    flatten(child)     # FOR LISTS
#####################################
# END OF CODE FOR LISTS
#---------------------------
# BEGIN CODE FOR DICTIONARIES
#####################################
for child_key in parent:
    child = parent[child_key]  # FOR DICTIONARIES
    flatten(child)
#####################################
# END OF CODE FOR DICTIONARIES
#####################################

Другие вопросы по теме