¿Cómo convierto una lista de diccionarios en un DataFrame de pandas?
Las otras respuestas son correctas, pero no se ha explicado mucho en términos de ventajas y limitaciones de estos métodos. El objetivo de esta publicación será mostrar ejemplos de estos métodos en diferentes situaciones, discutir cuándo usar (y cuándo no usar), y sugerir alternativas.
Dependiendo de la estructura y el formato de sus datos, hay situaciones en las que los tres métodos funcionan, o algunos funcionan mejor que otros, o algunos no funcionan en absoluto.
Considere un ejemplo muy artificial.
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}]
Esta lista consta de "registros" con cada clave presente. Este es el caso más simple que podrías encontrar.
# 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
Word en las orientaciones del diccionario: orient='index'
/'columns'
Antes de continuar, es importante hacer la distinción entre los diferentes tipos de orientaciones de diccionario y el apoyo con pandas. Hay dos tipos principales: "columnas" e "índice".
orient='columns'
Los diccionarios con la orientación de "columnas" tendrán sus claves correspondientes a las columnas en el DataFrame equivalente.
Por ejemplo, data
arriba está en las "columnas" orientar.
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: Si está utilizando pd.DataFrame.from_records
, se supone que la orientación es "columnas" (no puede especificar lo contrario), y los diccionarios se cargarán en consecuencia.
orient='index'
Con este oriente, se supone que las claves corresponden a valores de índice. Este tipo de datos es el más adecuado para 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
Este caso no se considera en el OP, pero aún es útil saberlo.
Establecer índice personalizado
Si necesita un índice personalizado en el DataFrame resultante, puede configurarlo utilizando el index=...
argumento.
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
Esto no es compatible con pd.DataFrame.from_dict
.
Manejo de llaves / columnas faltantes
Todos los métodos funcionan listos para usar cuando se manejan diccionarios con claves / valores de columna faltantes. Por ejemplo,
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
Lectura de subconjuntos de columnas
"¿Qué pasa si no quiero leer en cada columna"? Puede especificar esto fácilmente utilizando el columns=...
parámetro
Por ejemplo, del diccionario de ejemplo data2
anterior, si desea leer solo las columnas "A", "D" y "F", puede hacerlo pasando una lista:
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
Esto no es compatible pd.DataFrame.from_dict
con las "columnas" orientadas por defecto.
pd.DataFrame.from_dict(data2, orient='columns', columns=['A', 'B'])
ValueError: cannot use columns parameter with orient='columns'
Lectura de subconjuntos de filas
No es compatible con ninguno de estos métodos directamente . Tendrá que iterar sobre sus datos y realizar una eliminación inversa en el lugar a medida que itera. Por ejemplo, para extraer sólo el 0 º y 2 º filas de data2
arriba, puede utilizar:
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
para datos anidados
Una alternativa fuerte y robusta a los métodos descritos anteriormente es la json_normalize
función que funciona con listas de diccionarios (registros) y, además, también puede manejar diccionarios anidados.
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
Nuevamente, tenga en cuenta que los datos pasados json_normalize
deben estar en el formato de lista de diccionarios (registros).
Como se mencionó, json_normalize
también puede manejar diccionarios anidados. Aquí hay un ejemplo tomado de la documentación.
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
Para obtener más información sobre los argumentos meta
y record_path
, consulte la documentación.
Resumiendo
Aquí hay una tabla de todos los métodos discutidos anteriormente, junto con características / funcionalidades compatibles.
* Use orient='columns'
y luego transponga para obtener el mismo efecto que orient='index'
.