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.

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().


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

¿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.).


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

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

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).


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.


-3

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


no si las matrices dentro del dict son de diferente longitud
baxx
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.