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.
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, data
sopra è 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 data2
sopra, 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_dict
dall'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 data2
dall'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_normalize
per i dati nidificati
Un'alternativa forte e robusta ai metodi descritti sopra è la json_normalize
funzione 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_normalize
devono essere nel formato elenco di dizionari (record).
Come accennato, json_normalize
può 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 meta
e record_path
, consultare la documentazione.
Riassumendo
Ecco una tabella di tutti i metodi discussi sopra, insieme alle caratteristiche / funzionalità supportate.
* Utilizzare orient='columns'
e quindi trasporre per ottenere lo stesso effetto di orient='index'
.