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.

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


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

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


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

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

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


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.


-3

pd.DataFrame ([my_dict]) wystarczy!


nie, jeśli tablice w dyktandzie mają różną długość
baxx
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.