Ich möchte einen Pivot auf einem pandas DataFrame
ausführen, wobei der Index zwei Spalten und nicht eine enthält. Zum Beispiel ein Feld für das Jahr, eines für den Monat, ein 'item'-Feld, das' item 1 'und' item 2 'anzeigt und ein' value'-Feld mit numerischen Werten Ich möchte, dass der Index Jahr + Monat ist.
Die einzige Möglichkeit, dies zum Laufen zu bringen, bestand darin, die beiden Felder zu einem zusammenzufassen und sie dann wieder zu trennen. Gibt es einen besseren Weg?
Minimaler Code unten kopiert. Vielen Dank!
PS Ja, ich bin mir bewusst, dass es andere Fragen mit den Schlüsselwörtern 'Pivot' und 'Multi-Index' gibt, aber ich habe nicht verstanden, ob/wie sie mir bei dieser Frage helfen können.
import pandas as pd
import numpy as np
df= pd.DataFrame()
month = np.arange(1, 13)
values1 = np.random.randint(0, 100, 12)
values2 = np.random.randint(200, 300, 12)
df['month'] = np.hstack((month, month))
df['year'] = 2004
df['value'] = np.hstack((values1, values2))
df['item'] = np.hstack((np.repeat('item 1', 12), np.repeat('item 2', 12)))
# This doesn't work:
# ValueError: Wrong number of items passed 24, placement implies 2
# mypiv = df.pivot(['year', 'month'], 'item', 'value')
# This doesn't work, either:
# df.set_index(['year', 'month'], inplace=True)
# ValueError: cannot label index with a null key
# mypiv = df.pivot(columns='item', values='value')
# This below works but is not ideal:
# I have to first concatenate then separate the fields I need
df['new field'] = df['year'] * 100 + df['month']
mypiv = df.pivot('new field', 'item', 'value').reset_index()
mypiv['year'] = mypiv['new field'].apply( lambda x: int(x) / 100)
mypiv['month'] = mypiv['new field'] % 100
Sie können gruppieren und dann entstapeln.
>>> df.groupby(['year', 'month', 'item'])['value'].sum().unstack('item')
item item 1 item 2
year month
2004 1 33 250
2 44 224
3 41 268
4 29 232
5 57 252
6 61 255
7 28 254
8 15 229
9 29 258
10 49 207
11 36 254
12 23 209
Oder benutze pivot_table
:
>>> df.pivot_table(
values='value',
index=['year', 'month'],
columns='item',
aggfunc=np.sum)
item item 1 item 2
year month
2004 1 33 250
2 44 224
3 41 268
4 29 232
5 57 252
6 61 255
7 28 254
8 15 229
9 29 258
10 49 207
11 36 254
12 23 209
Ich glaube, wenn Sie item
in Ihren MultiIndex aufnehmen, können Sie einfach das Stapeln aufheben:
df.set_index(['year', 'month', 'item']).unstack(level=-1)
Dies ergibt:
value
item item 1 item 2
year month
2004 1 21 277
2 43 244
3 12 262
4 80 201
5 22 287
6 52 284
7 90 249
8 14 229
9 52 205
10 76 207
11 88 259
12 90 200
Es ist ein bisschen schneller als mit pivot_table
und ungefähr genauso schnell oder etwas langsamer als mit groupby
.