Convertir pandas dataframe de ancho a largo

Tengo un pandas.Dataframe con las siguientes columnas:

 a_1 ab_1 ac_1 a_2 ab_2 ac_2 2 3 4 5 6 7 

¿Cómo lo convierto en lo siguiente?

 a ab ac 2 3 4 5 6 7 

Estaba tratando de usar pandas melt para convertir de formato ancho a largo, pero no estoy seguro de la syntax.

Puede usar split para MultiIndex y luego remodelar por stack y el último uso reset_index para eliminar MultiIndex :

 df.columns = df.columns.str.split('_', expand=True) df = df.stack().reset_index(drop=True) print (df) a ab ac 0 2 3 4 1 5 6 7 

 df = df.stack().reset_index(level=0, drop=True) print (df) a ab ac 1 2 3 4 2 5 6 7 

Puedes reemplazar las columnas por un multi-índice y una stack:

 df.columns = pd.MultiIndex.from_tuples(df.columns.str.split('_').map(tuple)) df = df.stack() 

Aquí hay una forma de hacerlo:

Código:

 df.columns = pd.MultiIndex.from_tuples( [c.split('_') for c in df.columns], names=['col', 'row']) df.melt().pivot(index='row', columns='col', values='value') 

¿Cómo?

  1. Cree un pandas.MultiIndex para las columnas dividiendo en _ .

  2. melt el dataframe y luego pivot sobre los elementos de los nombres de columna originales.

Código de prueba:

 df = pd.DataFrame( data=[range(2, 8)], columns='a_1 ab_1 ac_1 a_2 ab_2 ac_2'.split() ) print(df) df.columns = pd.MultiIndex.from_tuples( [c.split('_') for c in df.columns], names=['col', 'row']) print(df.melt().pivot(index='row', columns='col', values='value')) 

Resultados:

  a_1 ab_1 ac_1 a_2 ab_2 ac_2 0 2 3 4 5 6 7 col a ab ac row 1 2 3 4 2 5 6 7 

pandas <0.20.0

Si usa pandas antes de 0.20.0, melt() como:

 print(pd.melt(df).pivot(index='row', columns='col', values='value')) 

Puede dividir el dataframe en dos, luego cambiar el nombre de las columnas y finalmente concatenarlas:

 cols = ['a', 'ab', 'ac'] df1 = df[["a_1", "ab_1", "ac_1"]] df2 = df[["a_2", "ab_2", "ac_2"]] df1.columns = cols df2.columns = cols df3 = pd.concat([df1, df2], ignore_index=True) 

Si desea usar pnd.melt , probablemente debería usar los parámetros value_vars y value_name :

 df_a = pnd.melt(df, value_vars=['a_1', 'a_2'], value_name='a')[['a']] df_ab = pnd.melt(df, value_vars=['ab_1', 'ab_2'], value_name='ab')[['ab']] df_ac = pnd.melt(df, value_vars=['ac_1', 'ac_2'], value_name='ac')[['ac']] df_final = df_a.join(df_b).join(df_c) 

Alternativamente, tomando un enfoque más funcional:

 col_prefixes = ['a', 'ab', 'ac'] df_cuts = map(lambda x: pnd.melt(df, value_vars=['%s_1' % x, '%s_2' % x], value_name=x)[[x]], col_prefixes) df_final = reduce(lambda x, y: x.join(y), df_cuts) 

Hay una función incorporada wide_to_long para más información en la documentación:

 In [115]: df Out[115]: a_1 ab_1 ac_1 a_2 ab_2 ac_2 0 2 3 4 5 6 7 In [116]: df['id'] = df.index In [117]: df Out[117]: a_1 ab_1 ac_1 a_2 ab_2 ac_2 id 0 2 3 4 5 6 7 0 In [118]: pd.wide_to_long(df, ['a','ab','ac'],i='id',j='num',sep='_') Out[118]: a ab ac id num 0 1 2 3 4 2 5 6 7