Панды "столбцы дочерних подзаписей (в виде списков диктов)" в более традиционный стиль вывода "SQL Join" - PullRequest
0 голосов
/ 31 августа 2018

Если у меня есть DataFrame, запустив следующий код:

listDics = [
        {
                'PersonId':'1','First':'A','Last':'B',
                'SomeChildren':[{'Col1':'x','Col2':'y'},{'Col1':'xx','Col2':'yy'}],
                'MoreChildren':[{'MC1':'blahX','MC2':'blahY'},{'MC1':'blahXX','MC2':'blahYY'},{'MC1':'blahXXX','MC2':'blahYYY'}]
        },
        {
                'PersonId':'2','First':'C','Last':'D',
                'SomeChildren':[{'Col1':'m','Col2':'n'},{'Col1':'mm','Col2':'nn'},{'Col1':'mmm','Col2':'nnn'}],
                'MoreChildren':[{'MC1':'blahM','MC2':'blahN'}]
        }
        ]
import pandas
df = pandas.DataFrame(listDics)

Сырье, это выглядит так:

PersonId First Last                                       SomeChildren                                       MoreChildren
       1     A    B  [{'Col1': 'x', 'Col2': 'y'}, {'Col1': 'xx', 'C...  [{'MC1': 'blahX', 'MC2': 'blahY'}, {'MC1': 'bl...
       2     C    D  [{'Col1': 'm', 'Col2': 'n'}, {'Col1': 'mm', 'C...                 [{'MC1': 'blahM', 'MC2': 'blahN'}]

Я хочу вывод, который выглядит следующим образом:

PersonId    First   Last    SomeChildren.Col1   SomeChildren.Col2   MoreChildren.MC1    MoreChildren.MC2
1           A       B       x                   y                   blahX               blahY
1           A       B       x                   y                   blahXX              blahYY
1           A       B       x                   y                   blahXXX             blahYYY
1           A       B       xx                  yy                  blahX               blahY
1           A       B       xx                  yy                  blahXX              blahYY
1           A       B       xx                  yy                  blahXXX             blahYYY
2           C       D       m                   n                   blahM               blahN
2           C       D       mm                  nn                  blahM               blahN
2           C       D       mmm                 nnn                 blahM               blahN

А также вывод, который выглядит так:

FK  Col1    Col2
1   x       y
1   xx      yy
2   m       n
2   mm      nn
2   mmm     nnn

Какой самый питоновский способ создания этих двух фреймов данных?

Хотя я могу придумать множество хитроумных способов сделать это (например, выполнять повторный импорт в Pandas различных фрагментов исходного списка диктов, слияния результирующих компонентных суб-фреймов и т. Д.) , я изо всех сил пытаюсь найти «правильный» способ добиться желаемого результата.

Примечание: можно предположить, что «списки диктов» внутри внешних ячеек всегда будут совместно использовать набор ключей от диктата к диктовке. Данные представляют собой дамп JSON из API продукта реляционной базы данных, поэтому все «списки различий» являются строками таблицы.

1 Ответ

0 голосов
/ 31 августа 2018

Я не уверен, что это слишком круто, но вот что-то:

import pandas as pd
from functools import reduce

df = pd.DataFrame(listDics)

cols = ['SomeChildren', 'MoreChildren']

def f(s):
    out = pd.concat([pd.DataFrame(x) for x in df[s]], keys = df.index)
    out = out.add_prefix(s + '.')
    out.index = out.index.get_level_values(0)

    return(out)

addl_dfs = list(map(f, cols))
df = df.drop(cols, axis = 1)

df_list = [df] + addl_dfs

df = reduce(lambda l, r: pd.merge(l, r, left_index = True, right_index = True), df_list)

Единственное предостережение в том, что все еще происходит слияние, о котором вы упоминаете в своем вопросе, и здесь «FK» - это индекс, а не PersonId. Одним из преимуществ этого является то, что он должен быть гибким в случае дополнительных вложенных «столбцов», таких как SomeChildren и MoreChildren.

В меньшем фрейме данных, размещенном в конце вашего вопроса, имена столбцов не имеют префиксов. Чтобы удалить их, вы можете использовать это (обратите внимание, что это не будет работать, если имена столбцов имеют точки с начала):

for d in addl_dfs:
    d.columns = d.columns.str.split('.').str.get(1)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...