2013-08-15 19 views
19

Al momento ho un DataFrame disposte come:UnPivot Pandas dati

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

e vorrei "UNPIVOT" i dati a guardare come:

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

Qual è il modo migliore per realizzare questo usando Pandas/Numpy?

risposta

23

Devi solo fare df.unstack() e questo creerà una serie MultiIndexed con mese come primo livello e l'anno come indice di secondo livello. Se vuoi che siano colonne, basta chiamare il numero reset_index().

>>> 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 
6

Un'altra soluzione potrebbe essere quella di utilizzare pandas.melt per evitare inutile creazione di un MultiIndex, anche se questo non è che costoso se il telaio è piccolo e con la mia soluzione si devono ancora creare un temporaneo per la " "fuso". Il coraggio di melt suggeriscono che sia id_vars e value vengono copiati dal id_vars creazione utilizza tile e value creazione utilizza df.values.ravel('F') che credo fa una copia, se i dati non sono in ordine Fortran.

EDIT: Io non sono esattamente sicuro quando viene fatta una copia quando ravel è chiamato in quanto il parametro order indica solo come si desidera che i dati leggere e la docstring dice una copia viene effettuata solo quando necessario.

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 
+0

Il down-elettore dovrebbe fare commenti? –

+0

Ah capisco. Sì, "migliore" era una scarsa scelta di parole. –