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

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

Это список имеющихся у меня словарей, которые необходимо преобразовать в фрейм данных. Я пытался использовать мультииндекс, но не смог преобразовать весь фрейм данных.

 response = [{
"name": "xyz",
"empId": "007",
"details": [{
        "address": [{
            "street": "x street",
            "city": "x city"
        }, {
            "street": "xx street",
            "city": "xx city"
        }],
        "country": "xxz country"
    },
    {
        "address": [{
            "street": "y street",
            "city": "y city"
        }, {
            "street": "yy street",
            "city": "yy city"
        }],
        "country": "yyz country"
    }
]
}]
  

Мне удалось получить внутренний список словарей в фрейм данных с помощью следующего кода:

 for i in details:    
    Country = i['country']

    street =[]
    city = []
    index = pd.MultiIndex.from_arrays([[Country]*len(i['address']), list(range(1,len(i['address']) 1))], names=['Country', 'SL No'])
    df=pd.DataFrame(columns=["Street","City"],index=index)
    if i['address']:
        for row in i['address']:
            street.append(row['street'])
            city.append(row['city'])

    df["Street"]=street
    df["City"]=city

    frames.append(df)
df_final=pd.concat(frames)
  

Полученный результат:

 Country     SL No   Street     City
xxz country 1       x street   x city
            2      xx street  xx city
yyz country 1       y street   y city
            2      yy street  yy city
  

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

Конечный результат, который я хочу:

 Name    EmpId    Country        Street     City
xyz     007      xxz country    x street   x city
                                xx street  xx city
                 yyz country    y street   y city
                                yy street  yy cit
  

Комментарии:

1. не могли бы вы добавить конечный формат вывода, который вы хотите

2. @HadiMir добавили конечный результат, который мне требуется.

Ответ №1:

Использовать json_normalize с DataFrame.set_index :

 df = pd.json_normalize(response,
                       record_path=['details','address'],
                       meta=['name','empId', ['address','country']]
                       )

df = df.set_index(['name','empId','address.country'])
print (df)
                               street     city
name empId address.country                    
xyz  007   xxz country       x street   x city
           xxz country      xx street  xx city
           yyz country       y street   y city
           yyz country      yy street  yy city
  

Для более старых версий pandas используйте:

 df = pd.io.json.json_normalize(response,
                               record_path=['details','address'],
                               meta=['name','empId', ['address','country']]
                       )
  

Редактировать:

Протестировано с несколькими значениями и работает хорошо:

 response = [{
"name": "xyz",
"empId": "007",
"details": [{
        "address": [{
            "street": "x street",
            "city": "x city"
        }, {
            "street": "xx street",
            "city": "xx city"
        }],
        "country": "xxz country"
    },
    {
        "address": [{
            "street": "y street",
            "city": "y city"
        }, {
            "street": "yy street",
            "city": "yy city"
        }],
        "country": "yyz country"
    }
]
},
            {
"name": "xyz1",
"empId": "0071",
"details": [{
        "address": [{
            "street": "x street1",
            "city": "x city1"
        }, {
            "street": "xx stree1t",
            "city": "xx city1"
        }],
        "country": "xxz country"
    },
    {
        "address": [{
            "street": "y street",
            "city": "y city"
        }, {
            "street": "yy street",
            "city": "yy city"
        }],
        "country": "yyz country"
    }
]
}]
  

 df = pd.json_normalize(response,
                       record_path=['details','address'],
                       meta=['name','empId', ['address','country']]
                       )

df = df.set_index(['name','empId','address.country'])
  

 print (df)
                                street      city
name empId address.country                      
xyz  007   xxz country        x street    x city
           xxz country       xx street   xx city
           yyz country        y street    y city
           yyz country       yy street   yy city
xyz1 0071  xxz country       x street1   x city1
           xxz country      xx stree1t  xx city1
           yyz country        y street    y city
           yyz country       yy street   yy city
  

Комментарии:

1. Да. Это служит цели. Но что, если у меня есть большой набор данных в том же формате, он должен быть повторен.

2. @laplace — Не уверен, что повторяется? Существует много файлов json и нужно повторить мое решение?

3. @jezrael. Мой набор данных такой большой, что мне придется перебирать набор данных и преобразовывать весь набор данных в df. Ваше решение отлично работает для ответа [0], что делать, если у меня есть ответ [1 ….n] .

4. @jezrael Мой плохой. Это работает. Есть ли способ переименовать ‘address.country’ на другое имя?

5. @laplace Конечно, используйте df. rename(columns='address.country' :'new') перед df = df.set_index(['name','empId','address.country'])

Ответ №2:

Насколько я знаю, нет простого способа сделать это, поскольку ваши данные содержат несколько уровней списков. Хотя это немного запутанно, следующее должно работать. Код будет итеративно explode перечислять и преобразовывать словари в столбцы с json_normalize помощью .

 df = pd.DataFrame.from_records(response)
df = df.explode('details', ignore_index=True)
df = pd.concat([df, pd.json_normalize(df['details'])], axis=1)
df = df.explode('address', ignore_index=True)
df = pd.concat([df, pd.json_normalize(df['address'])], axis=1)
df = df.drop(columns=['details', 'address'])
  

Результат:

   name empId      country     street     city
0  xyz   007  xxz country   x street   x city
1  xyz   007  xxz country  xx street  xx city
2  xyz   007  yyz country   y street   y city
3  xyz   007  yyz country  yy street  yy city
  

Примечание: для версий pandas старше 1.1.0 explode ignore_index параметр отсутствует. Вместо этого используйте reset_index(drop=True) после explode .

Кроме того, в более старых версиях pandas вам нужно использовать pd.io.json.json_normalize вместо pd.json_normalize .