Crear un marco de datos a partir de un diccionario donde las entradas tienen diferentes longitudes

114

Digamos que tengo un diccionario con 10 pares clave-valor. Cada entrada contiene una matriz numerosa. Sin embargo, la longitud de la matriz no es la misma para todos ellos.

¿Cómo puedo crear un marco de datos donde cada columna contiene una entrada diferente?

Cuando intento:

pd.DataFrame(my_dict)

Yo obtengo:

ValueError: arrays must all be the same length

¿Alguna forma de superar esto? Estoy feliz de que Pandas use NaNpara rellenar esas columnas para las entradas más cortas.

Josh
fuente

Respuestas:

132

En Python 3.x:

In [6]: d = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )

In [7]: pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in d.items() ]))
Out[7]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4

En Python 2.x:

reemplazar d.items()con d.iteritems().

Jeff
fuente
Estuve trabajando en este mismo problema recientemente, ¡y esto es mejor que lo que tenía! Una cosa a tener en cuenta, el relleno con NaN obligará a la serie dtype a float64, lo que puede ser problemático si necesita hacer cálculos matemáticos enteros.
mattexx
Siempre puedes hacer una pregunta - mucha gente las responde
Jeff
debe proporcionar MVCE como sugieren los comentarios
Jeff
3
@germ, es posible que desee importar la serie primero o hacer algo como pd.Series(...) (asumiendo import pandas as pden la sección de importación)
Nima Mousavi
5
Versión más compacta de esta respuesta:pd.DataFrame({k: pd.Series(l) for k, l in d.items()})
user553965
82

Aquí tienes una forma sencilla de hacerlo:

In[20]: my_dict = dict( A = np.array([1,2]), B = np.array([1,2,3,4]) )
In[21]: df = pd.DataFrame.from_dict(my_dict, orient='index')
In[22]: df
Out[22]: 
   0  1   2   3
A  1  2 NaN NaN
B  1  2   3   4
In[23]: df.transpose()
Out[23]: 
    A  B
0   1  1
1   2  2
2 NaN  3
3 NaN  4
dezzan
fuente
¿Hay otras opciones para 'indexar'?
sAguinaga
@sAguinaga Sí:, columnspero este ya es el predeterminado. Ver la documentación de pandas - pandas.DataFrame.from_dict
Murmel
15

A continuación, se muestra una forma de ordenar su sintaxis, pero aún hacer esencialmente lo mismo que estas otras respuestas:

>>> mydict = {'one': [1,2,3], 2: [4,5,6,7], 3: 8}

>>> dict_df = pd.DataFrame({ key:pd.Series(value) for key, value in mydict.items() })

>>> dict_df

   one  2    3
0  1.0  4  8.0
1  2.0  5  NaN
2  3.0  6  NaN
3  NaN  7  NaN

También existe una sintaxis similar para las listas:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame([ pd.Series(value) for value in mylist ])

>>> list_df

     0    1    2
0  1.0  2.0  3.0
1  4.0  5.0  NaN
2  6.0  NaN  NaN

Otra sintaxis de las listas es:

>>> mylist = [ [1,2,3], [4,5], 6 ]

>>> list_df = pd.DataFrame({ i:pd.Series(value) for i, value in enumerate(mylist) })

>>> list_df

   0    1    2
0  1  4.0  6.0
1  2  5.0  NaN
2  3  NaN  NaN

Es posible que, además, tenga que transponer el resultado y / o cambiar los tipos de datos de la columna (flotante, entero, etc.).

NaranjaSherbet
fuente
3

Si bien esto no responde directamente a la pregunta del OP. Encontré que esta es una excelente solución para mi caso cuando tenía matrices desiguales y me gustaría compartir:

de la documentación de pandas

In [31]: d = {'one' : Series([1., 2., 3.], index=['a', 'b', 'c']),
   ....:      'two' : Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}
   ....: 

In [32]: df = DataFrame(d)

In [33]: df
Out[33]: 
   one  two
a    1    1
b    2    2
c    3    3
d  NaN    4
user2015487
fuente
3

También puede utilizar pd.concatjunto axis=1con una lista de pd.Seriesobjetos:

import pandas as pd, numpy as np

d = {'A': np.array([1,2]), 'B': np.array([1,2,3,4])}

res = pd.concat([pd.Series(v, name=k) for k, v in d.items()], axis=1)

print(res)

     A  B
0  1.0  1
1  2.0  2
2  NaN  3
3  NaN  4
jpp
fuente
2

Ambas líneas siguientes funcionan perfectamente:

pd.DataFrame.from_dict(df, orient='index').transpose() #A

pd.DataFrame(dict([ (k,pd.Series(v)) for k,v in df.items() ])) #B (Better)

Pero con% timeit en Jupyter, tengo una relación de 4x la velocidad para B vs A, lo cual es bastante impresionante, especialmente cuando se trabaja con un gran conjunto de datos (principalmente con una gran cantidad de columnas / características).

Ismail Hachimi
fuente
1

Si no desea que se muestre NaNy tiene dos longitudes particulares, también funcionaría agregar un 'espacio' en cada celda restante.

import pandas

long = [6, 4, 7, 3]
short = [5, 6]

for n in range(len(long) - len(short)):
    short.append(' ')

df = pd.DataFrame({'A':long, 'B':short}]
# Make sure Excel file exists in the working directory
datatoexcel = pd.ExcelWriter('example1.xlsx',engine = 'xlsxwriter')
df.to_excel(datatoexcel,sheet_name = 'Sheet1')
datatoexcel.save()

   A  B
0  6  5
1  4  6
2  7   
3  3   

Si tiene más de 2 longitudes de entradas, es aconsejable crear una función que utilice un método similar.

Rohan Chandratre
fuente
-3

¡pd.DataFrame ([my_dict]) servirá!

john joy
fuente
no si las matrices dentro del dict son de diferente longitud
baxx