Erstellen eines Datenrahmens aus einem Wörterbuch, in dem Einträge unterschiedlich lang sind

114

Angenommen, ich habe ein Wörterbuch mit 10 Schlüssel-Wert-Paaren. Jeder Eintrag enthält ein Numpy-Array. Die Länge des Arrays ist jedoch nicht für alle gleich.

Wie kann ich einen Datenrahmen erstellen, in dem jede Spalte einen anderen Eintrag enthält?

Wenn ich es versuche:

pd.DataFrame(my_dict)

Ich bekomme:

ValueError: arrays must all be the same length

Wie kann man das überwinden? Ich bin froh, dass Pandas NaNdiese Spalten für die kürzeren Einträge auffüllen.

Josh
quelle

Antworten:

131

In 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

In Python 2.x:

ersetzen d.items()durch d.iteritems().

Jeff
quelle
Ich habe kürzlich an demselben Problem gearbeitet, und das ist besser als das, was ich hatte! Beachten Sie, dass durch das Auffüllen mit NaNs der Typ dtype auf float64 gezwungen wird. Dies kann problematisch sein, wenn Sie ganzzahlige Berechnungen durchführen müssen.
Mattexx
Sie können immer eine Frage stellen - viele Leute beantworten sie
Jeff
Sie müssen MVCE bereitstellen, wie aus den Kommentaren hervorgeht
Jeff
3
@germ Vielleicht möchten Sie zuerst die Serie importieren oder etwas Ähnliches tun pd.Series(...) (vorausgesetzt, import pandas as pdim Importabschnitt)
Nima Mousavi
5
Kompaktere Version dieser Antwort: pd.DataFrame({k: pd.Series(l) for k, l in d.items()})
user553965
81

Hier ist eine einfache Möglichkeit, dies zu tun:

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
quelle
Gibt es andere Optionen zum 'Indexieren'?
sAguinaga
@sAguinaga Ja: columnsaber das ist schon die Standardeinstellung. Siehe Pandas Dokumentation - Pandas.DataFrame.from_dict
Murmel
15

Im Folgenden finden Sie eine Möglichkeit, Ihre Syntax aufzuräumen, aber im Wesentlichen das Gleiche wie bei diesen anderen Antworten zu tun:

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

Eine ähnliche Syntax gibt es auch für Listen:

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

Eine andere Syntax für Listen lautet:

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

Möglicherweise müssen Sie das Ergebnis zusätzlich transponieren und / oder die Spaltendatentypen (float, integer usw.) ändern.

OrangeSherbet
quelle
3

Dies beantwortet zwar nicht direkt die Frage des OP. Ich fand, dass dies eine hervorragende Lösung für meinen Fall ist, wenn ich ungleiche Arrays hatte und Folgendes mitteilen möchte:

aus der pandas dokumentation

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

Sie können auch pd.concatzusammen axis=1mit einer Liste von pd.SeriesObjekten verwenden:

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

Beide folgenden Zeilen funktionieren perfekt:

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

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

Aber mit% timeit auf Jupyter habe ich ein Verhältnis von 4x Geschwindigkeit für B gegen A, was besonders bei der Arbeit mit einem riesigen Datensatz (hauptsächlich mit einer großen Anzahl von Spalten / Features) ziemlich beeindruckend ist.

Ismail Hachimi
quelle
1

Wenn Sie nicht möchten, dass es angezeigt wird NaNund Sie zwei bestimmte Längen haben, funktioniert das Hinzufügen eines Leerzeichens in jeder verbleibenden Zelle ebenfalls.

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   

Wenn Sie mehr als zwei Längen von Einträgen haben, ist es ratsam, eine Funktion zu erstellen, die eine ähnliche Methode verwendet.

Rohan Chandratre
quelle
-3

pd.DataFrame ([my_dict]) reicht aus!

John Joy
quelle
nicht, wenn die Arrays innerhalb des
Diktats