Converti un elenco di dizionari in un DataFrame panda


658

Ho un elenco di dizionari come questo:

[{'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'}]

E voglio trasformarlo in un panda DataFramecome questo:

      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

Nota: l'ordine delle colonne non ha importanza.

Come posso trasformare la lista dei dizionari in un DataFrame Panda come mostrato sopra?

Risposte:


951

Supponendo che dsia il tuo elenco di dadi, semplicemente:

pd.DataFrame(d)

3
Come si può usare una delle coppie chiave / valore come indice (es. Tempo)?
CatsLoveJazz,

6
@CatsLoveJazz Puoi solo fare df = df.set_index('time')dopo
joris,

1
@CatsLoveJazz No, ciò non è possibile durante la conversione da un dict.
joris,

6
A partire da Panda 0.19.2, non c'è menzione di questo nella documentazione, almeno non nei documenti perpandas.DataFrame
Leo Alekseyev

1
'{"":{"...Ricorda che per un dizionario nidificato usi l'approccio json_normalize, vedi la risposta dettagliata di @ cs95
Lorenz

136

Come posso convertire un elenco di dizionari in un DataFrame Panda?

Le altre risposte sono corrette, ma non è stato spiegato molto in termini di vantaggi e limiti di questi metodi. Lo scopo di questo post sarà quello di mostrare esempi di questi metodi in diverse situazioni, discutere quando usare (e quando non usare) e suggerire alternative.


DataFrame(), DataFrame.from_records()e.from_dict()

A seconda della struttura e del formato dei dati, ci sono situazioni in cui tutti e tre i metodi funzionano o alcuni funzionano meglio di altri o alcuni non funzionano affatto.

Considera un esempio molto ingegnoso.

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}]

Questo elenco è costituito da "record" con tutte le chiavi presenti. Questo è il caso più semplice che potresti incontrare.

# 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

Orientamenti parola su dizionario: orient='index'/'columns'

Prima di continuare, è importante fare una distinzione tra i diversi tipi di orientamenti del dizionario e supporto con i panda. Esistono due tipi principali: "colonne" e "indice".

orient='columns'
I dizionari con l'orientamento alle "colonne" avranno le chiavi corrispondenti alle colonne nel DataFrame equivalente.

Ad esempio, datasopra è nell'oriente "colonne".

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

Nota: se si sta utilizzando pd.DataFrame.from_records, si presume che l'orientamento sia "colonne" (non è possibile specificare diversamente) e i dizionari verranno caricati di conseguenza.

orient='index'
Con questo orientamento, si presume che le chiavi corrispondano ai valori dell'indice. Questo tipo di dati è più adatto per 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

Questo caso non è considerato nel PO, ma è comunque utile da sapere.

Impostazione dell'indice personalizzato

Se è necessario un indice personalizzato sul DataFrame risultante, è possibile impostarlo utilizzando l' index=...argomento.

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

Questo non è supportato da pd.DataFrame.from_dict.

Trattare con chiavi / colonne mancanti

Tutti i metodi funzionano immediatamente quando si gestiscono dizionari con valori di chiavi / colonna mancanti. Per esempio,

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

Lettura del sottoinsieme di colonne

"E se non volessi leggere in ogni singola colonna"? Puoi specificarlo facilmente usando il columns=...parametro

Ad esempio, dal dizionario di esempio data2sopra, se si desidera leggere solo le colonne "A", "D" e "F", è possibile farlo passando un elenco:

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

Questo non è supportato pd.DataFrame.from_dictdall'oriente predefinito "colonne".

pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])

ValueError: cannot use columns parameter with orient='columns'

Lettura del sottoinsieme di righe

Non supportato da uno di questi metodi direttamente . Dovrai scorrere i tuoi dati ed eseguire una cancellazione inversa sul posto mentre esegui l' iterazione. Ad esempio, per estrarre solo la 0a e la 2a riga data2dall'alto, puoi usare:

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 panacea: json_normalizeper i dati nidificati

Un'alternativa forte e robusta ai metodi descritti sopra è la json_normalizefunzione che funziona con elenchi di dizionari (record) e che può anche gestire dizionari nidificati.

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

Ancora una volta, tieni presente che i dati passati json_normalizedevono essere nel formato elenco di dizionari (record).

Come accennato, json_normalizepuò anche gestire dizionari nidificati. Ecco un esempio tratto dalla documentazione.

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

Per ulteriori informazioni sugli argomenti metae record_path, consultare la documentazione.


Riassumendo

Ecco una tabella di tutti i metodi discussi sopra, insieme alle caratteristiche / funzionalità supportate.

inserisci qui la descrizione dell'immagine

* Utilizzare orient='columns'e quindi trasporre per ottenere lo stesso effetto di orient='index'.


8
Woah! Va bene questo insieme all'unione di post SO appartengono all'API. Dovresti contribuire alla documentazione di Panda se non l'hai già fatto. Ted Petrou ha appena pubblicato un articolo su LinkedIn sulla popolarità dei panda su Stack Overflow e menziona che la mancanza di una buona documentazione contribuisce al volume di domande qui.
Scott Boston,

2
@ScottBoston Hai perfettamente ragione, l'ho sentito abbastanza volte ora che so che è qualcosa a cui dovrei pensare più seriamente. Penso che la documentazione possa essere un ottimo modo per aiutare gli utenti, più che postare domande che raggiungerebbero solo una parte dello stesso pubblico.
cs95,

1
è una bella risposta, penso che sia giunto il momento di ripassare quelle domande comuni nella versione più recente dei panda :-)
YOBEN_S

3
@ely: non è mai un motivo per non scrivere risposte qui, comunque . Ogni risposta può diventare obsoleta, ecco cosa abbiamo votato, e qui esistono diverse prospettive e obiettivi diversi, ed è sempre utile avere modi diversi di spiegare la stessa cosa.
Martijn Pieters

1
@MartijnPieters Metto in dubbio e non sono d'accordo con la tua ultima affermazione, ma nel complesso sono d'accordo con te. Non è sempre conveniente aggiungere una raccolta di risposte diverse alla stessa domanda, soprattutto se alcune delle risposte sono aggiornamenti o differenze condizionali basate su altre risposte. Nel peggiore dei casi, tali risposte possono essere distruttive in termini di valore se raccolte insieme (anziché utilizzare la risposta più aggiornata per modificare semplicemente la risposta più vecchia in uno stato più corretto). Ma ancora una volta, sono in gran parte d'accordo con te.
ely,

83

In Panda 16.2, ho dovuto fare pd.DataFrame.from_records(d)per farlo funzionare.


1
la cosa buona di questo approccio è che funziona anche condeque
MBZ

3
funziona bene con i panda 0.17.1con la soluzione di @joris
Anton Protopopov,

2
Usinig 0.14.1 e la soluzione @joris' non ha funzionato, ma questo fatto
mchen

13
In 0.18.1, si deve usare from_recordsse i dizionari non hanno tutti le stesse chiavi.
fredcallaway,

23

Puoi anche usare pd.DataFrame.from_dict(d)come:

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

La domanda riguarda la costruzione di un frame di dati da un elenco di dicts, non da un singolo dictcome si supponeva nella risposta.
a_guest,

@a_guest controlla la risposta aggiornata. Non sto assumendo.
shivsn,

2

So che alcune persone si imbatteranno in questo e non troveranno nulla qui aiuta. Il modo più semplice che ho trovato per farlo è così:

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)

Spero che questo aiuti qualcuno!


1
list=[{'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'}]

e semplice chiamata:

pd=DataFrame.from_dict(list, orient='columns', dtype=None)

print(pd)

0

Pyhton3: maggior parte delle soluzioni elencate in precedenza funzionano. Tuttavia, ci sono casi in cui row_number del dataframe non è richiesto e ogni riga (record) deve essere scritta singolarmente.

Il seguente metodo è utile in quel caso.

import csv

my file= 'C:\Users\John\Desktop\export_dataframe.csv'

records_to_save = data2 #used as in the thread. 


colnames = list[records_to_save[0].keys()] 
# remember colnames is a list of all keys. All values are written corresponding
# to the keys and "None" is specified in case of missing value 

with open(myfile, 'w', newline="",encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(colnames)
    for d in records_to_save:
        writer.writerow([d.get(r, "None") for r in colnames])

0

Per convertire un elenco di dizionari in un DataFrame Panda, è possibile utilizzare "append":

Abbiamo un dizionario chiamato dice DIC dispone di 30 voci di elenco ( list1, list2, ..., list30)

  1. step1: definisci una variabile per mantenere il tuo risultato (es: total_df )
  2. step2: inizializza total_dfconlist1
  3. step3: usa "for loop" per aggiungere tutti gli elenchi a total_df
total_df=list1
nums=Series(np.arange(start=2, stop=31))
for num in nums:
    total_df=total_df.append(dic['list'+str(num)])

Qual è il vantaggio di questo approccio rispetto gli approcci delineati da @ CS95 nella loro dettagliata risposta di due anni per quanto riguarda DataFrame(), DataFrame.from_records()e .from_dict()?
Jeremy Caney

Ho testato tutti i metodi sopra per un dizionario che ha 30 liste, ho ottenuto la risposta solo usando la funzione Aggiungi.
Armin Ahmadi Nasab
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.