Pandas распаковывает список диктовок по столбцам

У меня есть фрейм данных с полем fields, которое представляет собой список диктов (все строки имеют одинаковый формат). Вот как структурирован фрейм данных:

formId    fields
   123    [{'number': 1, 'label': 'Last Name', 'value': 'Doe'}, {'number': 2, 'label': 'First Name', 'value': 'John'}]

Я пытаюсь распаковать столбец fields, чтобы он выглядел так:

formId    Last Name    First Name
   123          Doe          John

Код, который у меня есть на данный момент:

for i,r in df.iterrows():
    for field in r['fields']:
        df.at[i, field['label']] = field['value']

Однако это не кажется самым эффективным способом. Есть ли лучший способ добиться этого?

🤔 А знаете ли вы, что...
С Python можно создавать кросс-платформенные приложения для Windows, macOS и Linux.


5
73
3

Ответы:

Вы можете использовать .apply и .concat для преобразования диктовок в серии. Наконец, .pivot для преобразования столбца в заголовки.

Данные:

import pandas as pd


data = {"formId": 123, "fields": [{'number': 1, 'label': 'Last Name', 'value': 'Doe'},
                                  {'number': 2, 'label': 'First Name', 'value': 'John'}]}
df = pd.DataFrame(data=data)

Код:

df = (pd
      .concat(objs=[df, df.pop("fields").apply(func=pd.Series)], axis=1)
      .pivot(index = "formId", columns = "label", values = "value")
      .reset_index()
      .rename_axis(mapper=None, axis=1)
      )

print(df)

Выход:

   formId First Name Last Name
0     123       John       Doe

Решено

Лично я бы построил новый фрейм данных:

df = pd.DataFrame(
    [
        {"formId": form_id, **{f["label"]: f["value"] for f in fields}}
        for form_id, fields in zip(df["formId"], df["fields"])
    ]
)

print(df)

Распечатки:

   formId Last Name First Name
0     123       Doe       John

Решение:

v = pd.concat([pd.json_normalize(x) for x in df["fields"]]).pivot_table(
    columns = "label", values = "value", aggfunc=list
)
out = df[["formId"]].join(v.explode(v.columns.tolist(), ignore_index=True))

Результат с использованием примера ввода из OP:

   formId First Name Last Name
0     123       John       Doe

Также работает для нескольких строк. Для этого примера введите:

df = pd.DataFrame(
    {
        "formId": [123, 456],
        "fields": [
            [
                {"number": 1, "label": "Last Name", "value": "Doe"},
                {"number": 2, "label": "First Name", "value": "John"},
            ],
            [
                {"number": 1, "label": "Last Name", "value": "Smith"},
                {"number": 2, "label": "First Name", "value": "Jack"},
            ],
        ],
    }
)

Результат:

   formId First Name Last Name
0     123       John       Doe
1     456       Jack     Smith