J'ai des données au format long et j'essaie de remodeler à large, mais il ne semble pas y avoir un moyen simple de le faire en utilisant fondre/empiler/désempiler:
Salesman Height product price
Knut 6 bat 5
Knut 6 ball 1
Knut 6 wand 3
Steve 5 pen 2
Devient:
Salesman Height product_1 price_1 product_2 price_2 product_3 price_3
Knut 6 bat 5 ball 1 wand 3
Steve 5 pen 2 NA NA NA NA
Je pense que Stata peut faire quelque chose comme ça avec la commande reshape.
Un simple pivot peut suffire à vos besoins mais c'est ce que j'ai fait pour reproduire la sortie souhaitée:
df['idx'] = df.groupby('Salesman').cumcount()
Le simple fait d'ajouter un compteur/index au sein du groupe vous permettra d'obtenir la plupart du chemin, mais les libellés des colonnes ne seront pas comme vous le souhaitez:
print df.pivot(index='Salesman',columns='idx')[['product','price']]
product price
idx 0 1 2 0 1 2
Salesman
Knut bat ball wand 5 1 3
Steve pen NaN NaN 2 NaN NaN
Pour se rapprocher de la sortie souhaitée, j'ai ajouté ce qui suit:
df['prod_idx'] = 'product_' + df.idx.astype(str)
df['prc_idx'] = 'price_' + df.idx.astype(str)
product = df.pivot(index='Salesman',columns='prod_idx',values='product')
prc = df.pivot(index='Salesman',columns='prc_idx',values='price')
reshape = pd.concat([product,prc],axis=1)
reshape['Height'] = df.set_index('Salesman')['Height'].drop_duplicates()
print reshape
product_0 product_1 product_2 price_0 price_1 price_2 Height
Salesman
Knut bat ball wand 5 1 3 6
Steve pen NaN NaN 2 NaN NaN 5
Edit: si vous voulez généraliser la procédure à plus de variables, je pense que vous pourriez faire quelque chose comme ceci (bien que cela ne soit pas assez efficace):
df['idx'] = df.groupby('Salesman').cumcount()
tmp = []
for var in ['product','price']:
df['tmp_idx'] = var + '_' + df.idx.astype(str)
tmp.append(df.pivot(index='Salesman',columns='tmp_idx',values=var))
reshape = pd.concat(tmp,axis=1)
@Luke a déclaré:
Je pense que Stata peut faire quelque chose comme ça avec la commande reshape.
Vous pouvez, mais je pense que vous avez également besoin d'un compteur dans le groupe pour obtenir la refonte en stata pour obtenir la sortie souhaitée:
+-------------------------------------------+
| salesman idx height product price |
|-------------------------------------------|
1. | Knut 0 6 bat 5 |
2. | Knut 1 6 ball 1 |
3. | Knut 2 6 wand 3 |
4. | Steve 0 5 pen 2 |
+-------------------------------------------+
Si vous ajoutez idx
, vous pouvez refaçonner dans stata
:
reshape wide product price, i(salesman) j(idx)
Un peu vieux mais je posterai ceci pour d'autres personnes.
Ce que vous voulez peut être atteint, mais vous ne devriez probablement pas le vouloir;) Pandas prend en charge les index hiérarchiques pour les lignes et les colonnes. Dans Python 2.7.x ...
from StringIO import StringIO
raw = '''Salesman Height product price
Knut 6 bat 5
Knut 6 ball 1
Knut 6 wand 3
Steve 5 pen 2'''
dff = pd.read_csv(StringIO(raw), sep='\s+')
print dff.set_index(['Salesman', 'Height', 'product']).unstack('product')
Produit une représentation probablement plus pratique que ce que vous recherchiez
price
product ball bat pen wand
Salesman Height
Knut 6 1 5 NaN 3
Steve 5 NaN NaN 2 NaN
L'avantage d'utiliser set_index et de désempiler par rapport à une seule fonction comme pivot est que vous pouvez diviser les opérations en petites étapes claires, ce qui simplifie le débogage.
pivoted = df.pivot('salesman', 'product', 'price')
p. 192 Python pour l'analyse des données
Voici une autre solution plus étoffée, tirée de site de Chris Albon .
raw_data = {'patient': [1, 1, 1, 2, 2],
'obs': [1, 2, 3, 1, 2],
'treatment': [0, 1, 0, 1, 0],
'score': [6252, 24243, 2345, 2342, 23525]}
df = pd.DataFrame(raw_data, columns = ['patient', 'obs', 'treatment', 'score'])
df.pivot(index='patient', columns='obs', values='score')
La solution de Karl D est au cœur du problème. Mais je trouve qu'il est beaucoup plus facile de tout faire pivoter (avec .pivot_table
à cause des deux colonnes d'index) puis sort
et affectez les colonnes pour réduire le MultiIndex
:
df['idx'] = df.groupby('Salesman').cumcount()+1
df = df.pivot_table(index=['Salesman', 'Height'], columns='idx',
values=['product', 'price'], aggfunc='first')
df = df.sort_index(axis=1, level=1)
df.columns = [f'{x}_{y}' for x,y in df.columns]
df = df.reset_index()
Salesman Height price_1 product_1 price_2 product_2 price_3 product_3
0 Knut 6 5.0 bat 1.0 ball 3.0 wand
1 Steve 5 2.0 pen NaN NaN NaN NaN