Unpivot Pandas Data

Actualmente tengo un DataFrame presentado como:

  Jan Feb Mar Apr ... 2001 1 12 12 19 2002 9 ... 2003 ... 

y me gustaría “separar” los datos para que parezcan:

 Date Value Jan 2001 1 Feb 2001 1 Mar 2001 12 ... Jan 2002 9 

¿Cuál es la mejor manera de lograr esto usando pandas / NumPy?

Solo tiene que hacer df.unstack() y eso creará una Serie MultiIndexed con mes como primer nivel y el año como índice de segundo nivel. Si desea que sean columnas, llame a reset_index() después de eso.

 >>> df Jan Feb 2001 3 4 2002 2 7 >>> df.unstack() Jan 2001 3 2002 2 Feb 2001 4 2002 7 >>> df = df.unstack().reset_index(name='value') >>> df level_0 level_1 value 0 Jan 2001 3 1 Jan 2002 2 2 Feb 2001 4 3 Feb 2002 7 >>> df.rename(columns={'level_0': 'month', 'level_1': 'year'}, inplace=True) >>> df month year value 0 Jan 2001 3 1 Jan 2002 2 2 Feb 2001 4 3 Feb 2002 7 

Otra solución sería usar pandas.melt para evitar la creación innecesaria de un MultiIndex , aunque esto no es tan costoso si su marco es pequeño y con mi solución todavía tiene que crear un temporal para los datos “fundidos”. Las agallas de melt sugieren que tanto id_vars como value se copian, ya que la creación de id_vars usa el tile y la creación de value usa df.values.ravel('F') que creo que hace una copia si sus datos no están en el orden de Fortran .

EDITAR: No estoy exactamente seguro de cuándo se realiza una copia cuando se llama a ravel ya que el parámetro de order solo indica cómo desea que se lean sus datos y la cadena de documentación dice que se hace una copia solo cuando es necesario.

 In [99]: mons Out[99]: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] In [100]: df = DataFrame(randn(201, len(mons)), columns=mons, index=map(str, arange(1901, 2102))) In [101]: df.head() Out[101]: Jan Feb Mar Apr May Jun Jul Aug Sep Oct \ 1901 1.141 -0.270 0.329 0.214 -1.030 0.324 -1.448 2.003 -0.061 0.477 1902 0.136 0.151 0.447 -0.493 1.329 1.410 0.020 -0.705 0.870 0.478 1903 -0.000 0.689 1.768 -0.057 -1.471 0.515 -0.315 0.703 2.511 0.592 1904 1.199 1.246 -0.255 0.182 -0.454 -0.452 1.074 0.178 2.495 -0.543 1905 1.073 1.375 -1.837 1.048 -0.139 -0.273 -0.958 -1.164 -1.012 0.950 Nov Dec 1901 0.102 0.122 1902 2.941 0.654 1903 0.347 -1.636 1904 -0.047 0.457 1905 1.277 -0.284 In [102]: df.reset_index(inplace=True) In [103]: df.head() Out[103]: index Jan Feb Mar Apr May Jun Jul Aug Sep Oct \ 0 1901 1.141 -0.270 0.329 0.214 -1.030 0.324 -1.448 2.003 -0.061 0.477 1 1902 0.136 0.151 0.447 -0.493 1.329 1.410 0.020 -0.705 0.870 0.478 2 1903 -0.000 0.689 1.768 -0.057 -1.471 0.515 -0.315 0.703 2.511 0.592 3 1904 1.199 1.246 -0.255 0.182 -0.454 -0.452 1.074 0.178 2.495 -0.543 4 1905 1.073 1.375 -1.837 1.048 -0.139 -0.273 -0.958 -1.164 -1.012 0.950 Nov Dec 0 0.102 0.122 1 2.941 0.654 2 0.347 -1.636 3 -0.047 0.457 4 1.277 -0.284 In [104]: res = pd.melt(df, id_vars=['index'], var_name=['months']) In [105]: res['date'] = res['months'] + ' ' + res['index'] In [106]: res.head() Out[106]: index months value date 0 1901 Jan 1.141 Jan 1901 1 1902 Jan 0.136 Jan 1902 2 1903 Jan -0.000 Jan 1903 3 1904 Jan 1.199 Jan 1904 4 1905 Jan 1.073 Jan 1905