Comment convertir une liste de dictionnaires en DataFrame pandas?
Les autres réponses sont correctes, mais peu a été expliqué en termes d'avantages et de limites de ces méthodes. Le but de cet article sera de montrer des exemples de ces méthodes dans différentes situations, de discuter quand utiliser (et quand ne pas utiliser) et suggérer des alternatives.
Selon la structure et le format de vos données, il existe des situations où les trois méthodes fonctionnent, ou certaines fonctionnent mieux que d'autres, ou certaines ne fonctionnent pas du tout.
Prenons un exemple très artificiel.
np.random.seed(0)
data = pd.DataFrame(
np.random.choice(10, (3, 4)), columns=list('ABCD')).to_dict('r')
print(data)
[{'A': 5, 'B': 0, 'C': 3, 'D': 3},
{'A': 7, 'B': 9, 'C': 3, 'D': 5},
{'A': 2, 'B': 4, 'C': 7, 'D': 6}]
Cette liste comprend des "enregistrements" avec toutes les clés présentes. C'est le cas le plus simple que vous puissiez rencontrer.
# The following methods all produce the same output.
pd.DataFrame(data)
pd.DataFrame.from_dict(data)
pd.DataFrame.from_records(data)
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
Mot sur les orientations du dictionnaire: orient='index'
/'columns'
Avant de continuer, il est important de faire la distinction entre les différents types d'orientations de dictionnaire et de soutien aux pandas. Il existe deux types principaux: "colonnes" et "index".
orient='columns'
Les dictionnaires avec l'orientation "colonnes" verront leurs clés correspondre aux colonnes du DataFrame équivalent.
Par exemple, data
ci-dessus est dans l'orientation "colonnes".
data_c = [
{'A': 5, 'B': 0, 'C': 3, 'D': 3},
{'A': 7, 'B': 9, 'C': 3, 'D': 5},
{'A': 2, 'B': 4, 'C': 7, 'D': 6}]
pd.DataFrame.from_dict(data_c, orient='columns')
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
Remarque: Si vous utilisez pd.DataFrame.from_records
, l'orientation est supposée être des "colonnes" (vous ne pouvez pas spécifier le contraire) et les dictionnaires seront chargés en conséquence.
orient='index'
Avec cet orient, les clés sont supposées correspondre aux valeurs d'index. Ce type de données est le mieux adapté pd.DataFrame.from_dict
.
data_i ={
0: {'A': 5, 'B': 0, 'C': 3, 'D': 3},
1: {'A': 7, 'B': 9, 'C': 3, 'D': 5},
2: {'A': 2, 'B': 4, 'C': 7, 'D': 6}}
pd.DataFrame.from_dict(data_i, orient='index')
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
Ce cas n'est pas pris en compte dans le PO, mais reste utile à connaître.
Définition d'un index personnalisé
Si vous avez besoin d'un index personnalisé sur le DataFrame résultant, vous pouvez le définir à l'aide de l' index=...
argument.
pd.DataFrame(data, index=['a', 'b', 'c'])
# pd.DataFrame.from_records(data, index=['a', 'b', 'c'])
A B C D
a 5 0 3 3
b 7 9 3 5
c 2 4 7 6
Ceci n'est pas pris en charge par pd.DataFrame.from_dict
.
Gérer les clés / colonnes manquantes
Toutes les méthodes fonctionnent immédiatement lors de la manipulation de dictionnaires avec des clés / valeurs de colonne manquantes. Par exemple,
data2 = [
{'A': 5, 'C': 3, 'D': 3},
{'A': 7, 'B': 9, 'F': 5},
{'B': 4, 'C': 7, 'E': 6}]
# The methods below all produce the same output.
pd.DataFrame(data2)
pd.DataFrame.from_dict(data2)
pd.DataFrame.from_records(data2)
A B C D E F
0 5.0 NaN 3.0 3.0 NaN NaN
1 7.0 9.0 NaN NaN NaN 5.0
2 NaN 4.0 7.0 NaN 6.0 NaN
Lecture d'un sous-ensemble de colonnes
"Et si je ne veux pas lire dans chaque colonne"? Vous pouvez facilement spécifier cela en utilisant lecolumns=...
paramètre.
Par exemple, à partir de l'exemple de dictionnaire data2
ci-dessus, si vous souhaitez lire uniquement les colonnes "A", "D" et "F", vous pouvez le faire en passant une liste:
pd.DataFrame(data2, columns=['A', 'D', 'F'])
# pd.DataFrame.from_records(data2, columns=['A', 'D', 'F'])
A D F
0 5.0 3.0 NaN
1 7.0 NaN 5.0
2 NaN NaN NaN
Ceci n'est pas supporté par pd.DataFrame.from_dict
avec les "colonnes" orient par défaut.
pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])
ValueError: cannot use columns parameter with orient='columns'
Lecture d'un sous-ensemble de lignes
Non pris en charge par aucune de ces méthodes directement . Vous devrez itérer sur vos données et effectuer une suppression inverse sur place au fur et à mesure de votre itération. Par exemple, pour extraire uniquement les 0 ème et 2 ème lignes d'en data2
haut, vous pouvez utiliser:
rows_to_select = {0, 2}
for i in reversed(range(len(data2))):
if i not in rows_to_select:
del data2[i]
pd.DataFrame(data2)
# pd.DataFrame.from_dict(data2)
# pd.DataFrame.from_records(data2)
A B C D E
0 5.0 NaN 3 3.0 NaN
1 NaN 4.0 7 NaN 6.0
La panacée: json_normalize
pour les données imbriquées
Une alternative forte et robuste aux méthodes décrites ci-dessus est la json_normalize
fonction qui fonctionne avec des listes de dictionnaires (enregistrements), et en plus peut également gérer des dictionnaires imbriqués.
pd.io.json.json_normalize(data)
A B C D
0 5 0 3 3
1 7 9 3 5
2 2 4 7 6
pd.io.json.json_normalize(data2)
A B C D E
0 5.0 NaN 3 3.0 NaN
1 NaN 4.0 7 NaN 6.0
Encore une fois, gardez à l'esprit que les données transmises json_normalize
doivent être au format liste de dictionnaires (enregistrements).
Comme mentionné, json_normalize
peut également gérer les dictionnaires imbriqués. Voici un exemple tiré de la documentation.
data_nested = [
{'counties': [{'name': 'Dade', 'population': 12345},
{'name': 'Broward', 'population': 40000},
{'name': 'Palm Beach', 'population': 60000}],
'info': {'governor': 'Rick Scott'},
'shortname': 'FL',
'state': 'Florida'},
{'counties': [{'name': 'Summit', 'population': 1234},
{'name': 'Cuyahoga', 'population': 1337}],
'info': {'governor': 'John Kasich'},
'shortname': 'OH',
'state': 'Ohio'}
]
pd.io.json.json_normalize(data_nested,
record_path='counties',
meta=['state', 'shortname', ['info', 'governor']])
name population state shortname info.governor
0 Dade 12345 Florida FL Rick Scott
1 Broward 40000 Florida FL Rick Scott
2 Palm Beach 60000 Florida FL Rick Scott
3 Summit 1234 Ohio OH John Kasich
4 Cuyahoga 1337 Ohio OH John Kasich
Pour plus d'informations sur les arguments meta
et record_path
, consultez la documentation.
Résumer
Voici un tableau de toutes les méthodes décrites ci-dessus, ainsi que les caractéristiques / fonctionnalités prises en charge.
* Utilisez orient='columns'
puis transposez pour obtenir le même effet que orient='index'
.