Pandas de largo a ancho remodelado, por dos variables

Tengo datos en formato largo y estoy tratando de remodelarlos a lo ancho, pero no parece haber una forma sencilla de hacerlo usando derretir / astackr / desastackr:

Salesman Height product price Knut 6 bat 5 Knut 6 ball 1 Knut 6 wand 3 Steve 5 pen 2 

Se convierte en

 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 

Creo que Stata puede hacer algo como esto con el comando remodelar.

Un simple pivote podría ser suficiente para sus necesidades, pero esto es lo que hice para reproducir su salida deseada:

 df['idx'] = df.groupby('Salesman').cumcount() 

Simplemente agregando un contador / índice dentro del grupo obtendrá la mayor parte del camino, pero las tags de las columnas no serán las que usted desea:

 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 

Para acercarme a la salida deseada, agregué lo siguiente:

 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 

Edición: si desea generalizar el procedimiento a más variables, creo que podría hacer algo como lo siguiente (aunque podría no ser lo suficientemente eficiente):

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

Creo que Stata puede hacer algo como esto con el comando remodelar.

Puede, pero creo que también necesita un contador dentro del grupo para obtener la remodelación en stata para obtener el resultado deseado:

  +-------------------------------------------+ | 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 agrega idx entonces podría hacer remodelación en stata :

 reshape wide product price, i(salesman) j(idx) 

Un poco viejo pero lo publicaré para otras personas.

Lo que quiere puede lograrse, pero probablemente no debería quererlo;) Pandas admite índices jerárquicos tanto para filas como para columnas. En 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') 

Produce una representación probablemente más conveniente de lo que buscabas

  price product ball bat pen wand Salesman Height Knut 6 1 5 NaN 3 Steve 5 NaN NaN 2 NaN 

La ventaja de usar set_index y desastackr frente a una función única como pivote es que puede dividir las operaciones en pequeños pasos claros, lo que simplifica la depuración.

 pivoted = df.pivot('salesman', 'product', 'price') 

pg. Python 192 para análisis de datos

Aquí hay otra solución más completa, tomada del sitio de Chris Albon .

Crear un dataframe “largo”

 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']) 

Hacer un dato “ancho”

 df.pivot(index='patient', columns='obs', values='score') 

La solución de Karl D llega al corazón del problema. Pero me parece que es mucho más fácil pivotar todo (con .pivot_table debido a las dos columnas de índice) y luego sort y asignar las columnas para contraer el 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() 

Salida:

  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 

Remodelando documentos están aquí

Está buscando pd.wide_to_long() (que es el análogo directo del comando stata)