Tworzenie ramki danych ze słownika, w którym wpisy mają różne długości

114

Powiedzmy, że mam słownik z 10 parami klucz-wartość. Każdy wpis zawiera tablicę numpy. Jednak długość tablicy nie jest taka sama dla wszystkich.

Jak mogę utworzyć ramkę danych, w której każda kolumna zawiera inny wpis?

Kiedy próbuję:

pd.DataFrame(my_dict)

Dostaję:

ValueError: arrays must all be the same length

Jakiś sposób, aby to przezwyciężyć? Cieszę się, że Pandy używają NaNtych kolumn do wypełniania krótszych wpisów.

Josh
źródło

Odpowiedzi:

132

W Pythonie 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

W Pythonie 2.x:

wymienić d.items()z d.iteritems().

Jeff
źródło
Ostatnio pracowałem nad tym samym problemem i to jest lepsze niż to, co miałem! Należy zwrócić uwagę na fakt, że dopełnienie wartościami NaN wymusi zmianę serii dtype na float64, co może być problematyczne, jeśli trzeba wykonywać obliczenia na liczbach całkowitych.
mattexx
zawsze możesz zadać pytanie - wiele osób na nie odpowiada
Jeff
musisz podać MVCE, jak sugerują komentarze
Jeff
3
@germ możesz najpierw zaimportować serię lub zrobić coś takiego pd.Series(...) (zakładając import pandas as pdw sekcji importu)
Nima Mousavi
5
Bardziej zwarta wersja tej odpowiedzi:pd.DataFrame({k: pd.Series(l) for k, l in d.items()})
user553965
82

Oto prosty sposób, aby to zrobić:

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
źródło
czy są inne opcje „indeksowania”?
sAguinaga,
@sAguinaga Tak: columnsale to już jest ustawienie domyślne. Zobacz dokumentację pand - pandas.DataFrame.from_dict
Murmel
15

Sposób na uporządkowanie składni, ale nadal zasadniczo to samo, co w przypadku innych odpowiedzi, znajduje się poniżej:

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

Podobna składnia istnieje również dla list:

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

Inna składnia list to:

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

Możesz dodatkowo transponować wynik i / lub zmienić typy danych w kolumnie (zmiennoprzecinkowe, całkowite itp.).

OrangeSherbet
źródło
3

Chociaż nie stanowi to bezpośredniej odpowiedzi na pytanie PO. Okazało się, że jest to doskonałe rozwiązanie w moim przypadku, gdy miałem nierówne tablice i chciałbym się podzielić:

z dokumentacji pand

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
źródło
3

Możesz także użyć pd.concatwraz axis=1z listą pd.Seriesobiektów:

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
źródło
2

Obie poniższe linie działają idealnie:

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

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

Ale z% timeit na Jupyter, mam stosunek prędkości 4x dla B do A, co jest dość imponujące, szczególnie podczas pracy z ogromnym zestawem danych (głównie z dużą liczbą kolumn / funkcji).

Ismail Hachimi
źródło
1

Jeśli nie chcesz, aby był wyświetlany NaNi masz dwie określone długości, dodanie „spacji” w każdej pozostałej komórce również zadziała.

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   

Jeśli masz więcej niż 2 długości wpisów, zaleca się utworzenie funkcji, która używa podobnej metody.

Rohan Chandratre
źródło
-3

pd.DataFrame ([my_dict]) wystarczy!

john joy
źródło
nie, jeśli tablice w dyktandzie mają różną długość
baxx