Je voudrais faire un pivot sur un pandas DataFrame
, l'index étant constitué de deux colonnes et non d'une. Par exemple, un champ pour l'année, un pour le mois, un champ 'item' qui indique 'item 1' et 'item 2' et un champ 'value' avec des valeurs numériques. Je veux que l'index soit l'année + le mois.
La seule manière pour que cela fonctionne est de combiner les deux champs en un, puis de les séparer à nouveau. Y a-t-il un meilleur moyen?
Code minimal copié ci-dessous. Merci beaucoup!
PS Oui, je suis conscient qu'il y a d'autres questions portant les mots-clés 'pivot' et 'multi-index', mais je ne comprenais pas si/comment elles pouvaient m'aider avec cette question.
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
Vous pouvez grouper puis désempiler.
>>> 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
Ou utiliser 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
Je crois que si vous incluez item
dans votre MultiIndex, vous pouvez simplement désempiler:
df.set_index(['year', 'month', 'item']).unstack(level=-1)
Cela donne:
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
C'est un peu plus rapide que d'utiliser pivot_table
, et à peu près à la même vitesse ou légèrement plus lentement que d'utiliser groupby
.