Aplanamiento eficiente de un dataframe pandas

Tengo un dataframe de pandas. Se parece a esto:

pd.DataFrame(data=np.arange(1,10).reshape(3,3), index=['A', 'B', 'C'], columns=['A', 'B', 'C']) 

pero tiene 100 filas y 100 columnas.

Quiero aplanarlo, para que se vea así:

 pd.DataFrame({'row' : ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'], 'col' : ['A', 'B', 'C']*3, 'val' : np.arange(1,10)}) 

¿Cuál es la forma más eficiente de hacer esto?

Gracias,

Jack

Opción 1
No estoy 100% seguro de la eficiencia, pero la forma más sencilla de hacerlo es con df.melt .

 df.rename_axis('row')\ .reset_index()\ .melt('row', value_name='val', var_name='col')\ .sort_values(['row', 'col']) row col val 0 AA 1 3 AB 2 6 AC 3 1 BA 4 4 BB 5 7 BC 6 2 CA 7 5 CB 8 8 CC 9 

opcion 2
Otra opción simple con stack

 v = df.stack().reset_index() v.columns=['row', 'col', 'val'] v 

O,

 df.stack().rename_axis(['row', 'col']).reset_index(name='val') 

  row col val 0 AA 1 1 AB 2 2 AC 3 3 BA 4 4 BB 5 5 BC 6 6 CA 7 7 CB 8 8 CC 9 

Esto debería ser rápido 🙂

 new_df=pd.DataFrame({'row':df.index.repeat(df.shape[1]),'col':df.columns.tolist()*len(df),'val':np.concatenate(df.values)}) new_df Out[343]: col row val 0 AA 1 1 BA 2 2 CA 3 3 AB 4 4 BB 5 5 CB 6 6 AC 7 7 BC 8 8 CC 9 

Método 1

Enfoque NumPy

 # https://stackoverflow.com/a/11146645/ @senderle def cartesian_product(*arrays): la = len(arrays) dtype = np.result_type(*arrays) arr = np.empty([len(a) for a in arrays] + [la], dtype=dtype) for i, a in enumerate(np.ix_(*arrays)): arr[...,i] = a return arr.reshape(-1, la) def flatten_dataframe(df): c = df.columns.values.astype(str) i = df.index.values.astype(str) df_out = pd.DataFrame(cartesian_product(i,c),columns=[['row','col']]) df_out['val'] = df.values.ravel() return df_out 

Ejecución de la muestra

 In [598]: df Out[598]: ABC P 1 2 3 Q 4 5 6 R 7 8 9 In [599]: flatten_dataframe(df) Out[599]: row col val 0 PA 1 1 PB 2 2 PC 3 3 QA 4 4 QB 5 5 QC 6 6 RA 7 7 RB 8 8 RC 9 

Método # 2: object dtype dataframe

Si está de acuerdo con el dataframe de dtype de objetos, aquí hay otra manera:

 def flatten_dataframe_obj(df): c = df.columns.values.astype(str) i = df.index.values.astype(str) m = len(i) n = len(c) out = np.empty((m,n,3),dtype=object) out[...,0] = i[:,None] out[...,1] = c out[...,2] = df.values return pd.DataFrame(out.reshape(-1,3), columns=[['row','col','val']])