web-dev-qa-db-fra.com

Convertir une liste de dictionnaires en un pandas _ DataFrame

J'ai une liste de dictionnaires comme ceci:

[{'points': 50, 'time': '5:00', 'year': 2010}, 
{'points': 25, 'time': '6:00', 'month': "february"}, 
{'points':90, 'time': '9:00', 'month': 'january'}, 
{'points_h1':20, 'month': 'june'}]

Et je veux transformer cela en un pandas DataFrame comme ceci:

      month  points  points_h1  time  year
0       NaN      50        NaN  5:00  2010
1  february      25        NaN  6:00   NaN
2   january      90        NaN  9:00   NaN
3      june     NaN         20   NaN   NaN

Remarque: l'ordre des colonnes n'a pas d'importance.

Comment transformer la liste des dictionnaires en un pandas DataFrame, comme indiqué ci-dessus?

502
appleLover

Supposons que d soit votre liste de dict, simplement:

pd.DataFrame(d)
732
joris

Dans pandas16.2, je devais faire pd.DataFrame.from_records(d) pour que cela fonctionne.

76
szeitlin

Comment convertir une liste de dictionnaires en un pandas DataFrame?

Les autres réponses sont correctes, mais peu d'explications ont été données sur les avantages et les inconvénients de ces méthodes. Le but de cet article sera de montrer des exemples de ces méthodes dans différentes situations, de déterminer quand utiliser (et quand ne pas utiliser) et de suggérer des alternatives.


DataFrame() , DataFrame.from_records() et .from_dict()

Selon la structure et le format de vos données, il existe des situations dans lesquelles 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 dictionnaires et le soutien aux pandas. Il existe deux types principaux: "colonnes" et "index".

_orient='columns'_
Dans les dictionnaires ayant l’orientation "colonnes", leurs clés correspondent 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 autrement) et les dictionnaires seront chargés en conséquence.

_orient='index'_
Avec cet orient, les touches sont supposées correspondre aux valeurs d'index. Ce type de données convient mieux pour _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 il reste utile de le savoir.

Définition d'un index personnalisé

Si vous avez besoin d'un index personnalisé sur la DataFrame résultante, vous pouvez le définir à l'aide de l'argument _index=..._.

_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 supporté par _pd.DataFrame.from_dict_.

Traitement des clés/colonnes manquantes

Toutes les méthodes fonctionnent prêtes à l'emploi lors de la gestion 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 du sous-ensemble de colonnes

"Et si je ne veux pas lire dans chaque colonne"? Vous pouvez facilement spécifier cela à l'aide du paramètre _columns=..._.

Par exemple, à partir du dictionnaire d'exemple de _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" par défaut orient.

_pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])
_
_ValueError: cannot use columns parameter with orient='columns'
_

Lecture du sous-ensemble de lignes

Non pris en charge par l'une de ces méthodes directement . Vous devrez parcourir vos données et effectuer un suppression inverse sur place au fur et à mesure de votre itération. Par exemple, pour extraire uniquement le 0th et 2dakota du Nord lignes de _data2_ ci-dessus, 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 fonction _json_normalize_ qui fonctionne avec des listes de dictionnaires (enregistrements) et qui permet également de 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, n'oubliez pas que les données transmises à _json_normalize_ doivent être au format liste de dictionnaires (enregistrements).

Comme indiqué, _json_normalize_ peut également gérer des 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ésumé

Voici un tableau de toutes les méthodes décrites ci-dessus, ainsi que des fonctionnalités/fonctionnalités prises en charge.

enter image description here

* Utilisez _orient='columns'_ puis transposez pour obtenir le même effet que _orient='index'_.

72
cs95

Vous pouvez également utiliser pd.DataFrame.from_dict(d) comme:

In [8]: d = [{'points': 50, 'time': '5:00', 'year': 2010}, 
   ...: {'points': 25, 'time': '6:00', 'month': "february"}, 
   ...: {'points':90, 'time': '9:00', 'month': 'january'}, 
   ...: {'points_h1':20, 'month': 'june'}]

In [12]: pd.DataFrame.from_dict(d)
Out[12]: 
      month  points  points_h1  time    year
0       NaN    50.0        NaN  5:00  2010.0
1  february    25.0        NaN  6:00     NaN
2   january    90.0        NaN  9:00     NaN
3      june     NaN       20.0   NaN     NaN
18
shivsn

Je sais que quelques personnes tomberont sur cela et ne trouveront rien qui puisse l’aider. La façon la plus simple que j'ai trouvée de le faire est la suivante:

dict_count = len(dict_list)
df = pd.DataFrame(dict_list[0], index=[0])
for i in range(1,dict_count-1):
    df = df.append(dict_list[i], ignore_index=True)

J'espère que ça aide quelqu'un!

0
scottapotamus