2014-10-30 33 views
19

Ho il seguente dataframe:Pandas mese groupby e anno

Date  abc xyz 
01-Jun-13 100 200 
03-Jun-13 -20 50 
15-Aug-13 40  -5 
20-Jan-14 25  15 
21-Feb-14 60  80 

ho bisogno di raggruppare i dati per anno e mese. es .: Gruppo entro gennaio 2013, febbraio 2013, marzo 2013 ecc ... Utilizzerò i dati appena raggruppati per creare un grafico che mostra abc vs xyz per anno/mese.

Ho provato varie combinazioni di groupby e somma ma proprio non riesco a trovare nulla per funzionare.

Grazie per l'assistenza.

risposta

39

È possibile utilizzare o resample o TimeGrouper (che ricampionare utilizza sotto il cofano).

Innanzitutto, fare in modo che la colonna datetime sia effettivamente datata (colpirla con pd.to_datetime). E 'più facile se si aveva un DatetimeIndex:

In [11]: df1 
Out[11]: 
      abc xyz 
Date 
2013-06-01 100 200 
2013-06-03 -20 50 
2013-08-15 40 -5 
2014-01-20 25 15 
2014-02-21 60 80 

In [12]: g = df1.groupby(pd.TimeGrouper("M"))  # DataFrameGroupBy (grouped by Month) 

In [13]: g.sum() 
Out[13]: 
      abc xyz 
Date 
2013-06-30 80 250 
2013-07-31 NaN NaN 
2013-08-31 40 -5 
2013-09-30 NaN NaN 
2013-10-31 NaN NaN 
2013-11-30 NaN NaN 
2013-12-31 NaN NaN 
2014-01-31 25 15 
2014-02-28 60 80 

In [14]: df1.resample("M", how='sum')  # the same 
Out[14]: 
      abc xyz 
Date 
2013-06-30 40 125 
2013-07-31 NaN NaN 
2013-08-31 40 -5 
2013-09-30 NaN NaN 
2013-10-31 NaN NaN 
2013-11-30 NaN NaN 
2013-12-31 NaN NaN 
2014-01-31 25 15 
2014-02-28 60 80 

avevo pensato il seguente avrebbe funzionato, ma non (a causa di as_index non essere rispettati non sono sicuro?.), I' m compreso questo nell'interesse degli interessi.

Se si tratta di una colonna (! Deve essere una colonna datetime64 come ho detto, ha colpito con to_datetime), è possibile utilizzare il PeriodIndex:

In [21]: df 
Out[21]: 
     Date abc xyz 
0 2013-06-01 100 200 
1 2013-06-03 -20 50 
2 2013-08-15 40 -5 
3 2014-01-20 25 15 
4 2014-02-21 60 80 

In [22]: pd.DatetimeIndex(df.Date).to_period("M") # old way 
Out[22]: 
<class 'pandas.tseries.period.PeriodIndex'> 
[2013-06, ..., 2014-02] 
Length: 5, Freq: M 

In [23]: per = df.Date.dt.to_period("M") # new way to get the same 

In [24]: g = df.groupby(per) 

In [25]: g.sum() # dang not quite what we want (doesn't fill in the gaps) 
Out[25]: 
     abc xyz 
2013-06 80 250 
2013-08 40 -5 
2014-01 25 15 
2014-02 60 80 

per ottenere il risultato desiderato dobbiamo reindicizzare. ..

+0

Grazie per l'aiuto. Non riuscivo a far funzionare TimeGrouper, ma resample ("M") ha fatto il trucco. Comunque solo fyi, richiedeva l'argomento how = 'sum'. Il mio unico problema ora è che la trama sta usando il pieno datetime per le etichette tick. Ho bisogno di mostrare solo il mese e l'anno per ogni barra. Grazie ancora. – darkpool

7

Ci sono diversi modi per farlo.

  • Ho creato il riquadro dati per mostrare le diverse tecniche per filtrare i dati.
df = pd.DataFrame({'Date':['01-Jun-13','03-Jun-13', '15-Aug-13', '20-Jan-14', '21-Feb-14'], 

'abc': [100, -20,40,25,60], 'xyz': [200,50, -5,15,80]})

  • I mesi separati/anno/giorno e mese-anno separato come hai spiegato.
def getMonth(s): 
    return s.split("-")[1] 

def getDay(s): 
    return s.split("-")[0] 

def getYear(s): 
    return s.split("-")[2] 

def getYearMonth(s): 
    return s.split("-")[1]+"-"+s.split("-")[2] 
  • ho creato nuove colonne: year, month, day e 'yearMonth'. Nel tuo caso, hai bisogno di entrambi. Si gruppo utilizzando due colonne 'year','month' o possibile utilizzando una colonna yearMonth
df['year']= df['Date'].apply(lambda x: getYear(x)) 
df['month']= df['Date'].apply(lambda x: getMonth(x)) 
df['day']= df['Date'].apply(lambda x: getDay(x)) 
df['YearMonth']= df['Date'].apply(lambda x: getYearMonth(x)) 

uscita:

 Date abc xyz year month day YearMonth 
0 01-Jun-13 100 200 13 Jun 01 Jun-13 
1 03-Jun-13 -20 50 13 Jun 03 Jun-13 
2 15-Aug-13 40 -5 13 Aug 15 Aug-13 
3 20-Jan-14 25 15 14 Jan 20 Jan-14 
4 21-Feb-14 60 80 14 Feb 21 Feb-14 
  • Si può passare attraverso i diversi gruppi in groupby (..) articoli .

In questo caso, ci si raggruppano da due colonne:

for key,g in df.groupby(['year','month']): 
    print key,g 

uscita:

('13', 'Jun')   Date abc xyz year month day YearMonth 
0 01-Jun-13 100 200 13 Jun 01 Jun-13 
1 03-Jun-13 -20 50 13 Jun 03 Jun-13 
('13', 'Aug')   Date abc xyz year month day YearMonth 
2 15-Aug-13 40 -5 13 Aug 15 Aug-13 
('14', 'Jan')   Date abc xyz year month day YearMonth 
3 20-Jan-14 25 15 14 Jan 20 Jan-14 
('14', 'Feb')   Date abc xyz year month day YearMonth 

In questo caso, ci si raggruppano da una colonna:

for key,g in df.groupby(['YearMonth']): 
    print key,g 

uscita:.

Jun-13   Date abc xyz year month day YearMonth 
0 01-Jun-13 100 200 13 Jun 01 Jun-13 
1 03-Jun-13 -20 50 13 Jun 03 Jun-13 
Aug-13   Date abc xyz year month day YearMonth 
2 15-Aug-13 40 -5 13 Aug 15 Aug-13 
Jan-14   Date abc xyz year month day YearMonth 
3 20-Jan-14 25 15 14 Jan 20 Jan-14 
Feb-14   Date abc xyz year month day YearMonth 
4 21-Feb-14 60 80 14 Feb 21 Feb-14 
  • Nel caso in cui l'accesso alla voglia elemento specifico, è possibile utilizzare get_group

df.groupby di stampa ([ 'annoMese']) get_group ('Jun-13')

Uscita:

 Date abc xyz year month day YearMonth 
0 01-Jun-13 100 200 13 Jun 01 Jun-13 
1 03-Jun-13 -20 50 13 Jun 03 Jun-13 
  • Simile a get_group. Questo hack potrebbe aiutare a filtrare i valori e ottenere i valori raggruppati.

Anche questo darebbe lo stesso risultato.

print df[df['YearMonth']=='Jun-13'] 

uscita:

 Date abc xyz year month day YearMonth 
0 01-Jun-13 100 200 13 Jun 01 Jun-13 
1 03-Jun-13 -20 50 13 Jun 03 Jun-13 

È possibile selezionare l'elenco dei abc o xyz valori durante Jun-13

print df[df['YearMonth']=='Jun-13'].abc.values 
print df[df['YearMonth']=='Jun-13'].xyz.values 

uscita:

[100 -20] #abc values 
[200 50] #xyz values 

Puoi usare questo per passare attraverso le date che hai classificato come "year-month" e applicare cretiria su di esso per ottenere dati correlati.

for x in set(df.YearMonth): 
    print df[df['YearMonth']==x].abc.values 
    print df[df['YearMonth']==x].xyz.values 

Consiglio anche controllare questo answer pure.

+0

Per chiunque abbia le date in questo formato '2016-08-11', cambia' def getYearMonth (s): return s.split ("-") [1] + "-" + s.split ("-") [2] 'a def getYearMonth (s): return s.split ("-") [0] + "-" + s.split ("-") [1] 'per ottenere l'output di' 2016-08' –

23

Perché non tenerlo semplice ?!

GB=DF.groupby([(DF.index.year),(DF.index.month)]).sum() 

dando,

print(GB) 
     abc xyz 
2013 6 80 250 
    8 40 -5 
2014 1 25 15 
    2 60 80 

e quindi si può tracciare come chiesto utilizzando,

GB.plot('abc','xyz',kind='scatter') 
0

si può anche fare con la creazione di una colonna stringa con l'anno e il mese come segue :

df['date'] = df.index 
df['year-month'] = df['date'].apply(lambda x: str(x.year) + ' ' + str(x.month)) 
grouped = df.groupby('year-month') 

Tuttavia, non mantiene l'ordine quando si esegue il looping sui gruppi, ad es.

for name, group in grouped: 
    print(name) 

Will dare:

2007 11 
2007 12 
2008 1 
2008 10 
2008 11 
2008 12 
2008 2 
2008 3 
2008 4 
2008 5 
2008 6 
2008 7 
2008 8 
2008 9 
2009 1 
2009 10 

Allora, se si vuole mantenere l'ordine, si deve fare come suggerito da @ Q-uomo al di sopra:

grouped = df.groupby([df.index.year, df.index.month]) 

Ciò manterrà l'ordine nel ciclo precedente:

(2007, 11) 
(2007, 12) 
(2008, 1) 
(2008, 2) 
(2008, 3) 
(2008, 4) 
(2008, 5) 
(2008, 6) 
(2008, 7) 
(2008, 8) 
(2008, 9) 
(2008, 10)