2012-04-04 6 views
21

Ho una serie di volte con temperatura e radiazione in un panda dataframe. La risoluzione temporale è di 1 minuto a passi regolari.Come ricampionare un dataframe con diverse funzioni applicate a ciascuna colonna?

import datetime 
import pandas as pd 
import numpy as np 

date_times = pd.date_range(datetime.datetime(2012, 4, 5, 8, 0), 
          datetime.datetime(2012, 4, 5, 12, 0), 
          freq='1min') 
tamb = np.random.sample(date_times.size) * 10.0 
radiation = np.random.sample(date_times.size) * 10.0 
frame = pd.DataFrame(data={'tamb': tamb, 'radiation': radiation}, 
        index=date_times) 
frame 
<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 241 entries, 2012-04-05 08:00:00 to 2012-04-05 12:00:00 
Freq: T 
Data columns: 
radiation 241 non-null values 
tamb   241 non-null values 
dtypes: float64(2) 

Come posso down-campione questo dataframe ad una risoluzione di un'ora, il calcolo del oraria significare per la temperatura e l'orario somma per le radiazioni?

risposta

41

Con panda 0.18 l'API di ricampionamento è stata modificata (vedere docs). Così per i panda> = 0,18 la risposta è:

In [31]: frame.resample('1H').agg({'radiation': np.sum, 'tamb': np.mean}) 
Out[31]: 
         tamb radiation 
2012-04-05 08:00:00 5.161235 279.507182 
2012-04-05 09:00:00 4.968145 290.941073 
2012-04-05 10:00:00 4.478531 317.678285 
2012-04-05 11:00:00 4.706206 335.258633 
2012-04-05 12:00:00 2.457873 8.655838 

Old Risposta:

sto rispondendo alla mia domanda per riflettere i cambiamenti relativi alla serie temporali in pandas >= 0.8 (tutte le altre risposte sono obsoleti).

Uso panda> = 0.8 la risposta è:

In [30]: frame.resample('1H', how={'radiation': np.sum, 'tamb': np.mean}) 
Out[30]: 
         tamb radiation 
2012-04-05 08:00:00 5.161235 279.507182 
2012-04-05 09:00:00 4.968145 290.941073 
2012-04-05 10:00:00 4.478531 317.678285 
2012-04-05 11:00:00 4.706206 335.258633 
2012-04-05 12:00:00 2.457873 8.655838 
+2

Questo può essere esteso a un elenco di funzioni per colonna: 'frame.resample ('1H', how = {'radiation': [np.sum, np.min], 'tamb': np.mean})'.Il DataFrame risultante ha un MultiIndex sulle sue colonne, con il nome della colonna originale come livello 0 e il nome della funzione come livello 1. –

+1

Per aggiungere al mio commento precedente: invece di un elenco di funzioni per colonna, puoi anche usare un dizionario, dove la chiave è il nuovo nome della colonna e il valore è la funzione da utilizzare: 'frame.resample ('1H', how = {'radiation': {'sum_rad': np.sum, 'min_rad': np.min} , 'tamb': np.mean}) ' –

+0

dire se si desidera aggiungere una nuova colonna al risultato, come count() di ogni riga nel periodo di ricampionamento. – codingknob

0

è necessario utilizzare groupby come tale:

grouped = frame.groupby(lambda x: x.hour) 
grouped.agg({'radiation': np.sum, 'tamb': np.mean}) 
# Same as: grouped.agg({'radiation': 'sum', 'tamb': 'mean'}) 

con l'essere uscita:

 radiation  tamb 
key_0      
8  298.581107 4.883806 
9  311.176148 4.983705 
10  315.531527 5.343057 
11  288.013876 6.022002 
12  5.527616 8.507670 

Quindi, in sostanza sto fessurazioni sulle valore un'ora e poi calcolando la media di tamb ed il somma di radiation e ritorno del DataFrame (approccio simile a R ddply). Per maggiori informazioni vorrei controllare la pagina della documentazione per groupby e il post del blog this.

Edit: Per effettuare questa scala un po 'meglio si potrebbe gruppo sia sul giorno e l'ora in quanto tale:

grouped = frame.groupby(lambda x: (x.day, x.hour)) 
grouped.agg({'radiation': 'sum', 'tamb': 'mean'}) 
      radiation  tamb 
key_0       
(5, 8) 298.581107 4.883806 
(5, 9) 311.176148 4.983705 
(5, 10) 315.531527 5.343057 
(5, 11) 288.013876 6.022002 
(5, 12) 5.527616 8.507670 
3

È inoltre possibile downsample utilizzando il metodo di pandas.DateRange objectsasof.

In [21]: hourly = pd.DateRange(datetime.datetime(2012, 4, 5, 8, 0), 
...       datetime.datetime(2012, 4, 5, 12, 0), 
...       offset=pd.datetools.Hour()) 

In [22]: frame.groupby(hourly.asof).size() 
Out[22]: 
key_0 
2012-04-05 08:00:00 60 
2012-04-05 09:00:00 60 
2012-04-05 10:00:00 60 
2012-04-05 11:00:00 60 
2012-04-05 12:00:00 1 
In [23]: frame.groupby(hourly.asof).agg({'radiation': np.sum, 'tamb': np.mean}) 
Out[23]: 
        radiation tamb 
key_0         
2012-04-05 08:00:00 271.54  4.491 
2012-04-05 09:00:00 266.18  5.253 
2012-04-05 10:00:00 292.35  4.959 
2012-04-05 11:00:00 283.00  5.489 
2012-04-05 12:00:00 0.5414  9.532 
+0

+1 per l'utilizzo di 'DateRange.asof' – diliop

3

per stuzzicare voi, in panda 0.8.0 (in fase di sviluppo pesante nel ramo timeseries su GitHub), sarete in grado di fare:

In [5]: frame.convert('1h', how='mean') 
Out[5]: 
        radiation  tamb 
2012-04-05 08:00:00 7.840989 8.446109 
2012-04-05 09:00:00 4.898935 5.459221 
2012-04-05 10:00:00 5.227741 4.660849 
2012-04-05 11:00:00 4.689270 5.321398 
2012-04-05 12:00:00 4.956994 5.093980 

I metodi di cui sopra sono a destra strategia con l'attuale versione di produzione dei panda.

+0

Grazie, ma quello che voglio avere sarebbe qualcosa come' frame.convert ('1h', how = {'radiation': 'sum,' tamb ':' mean '}) '. È un'opzione in 0.8? – bmu

+0

@ Wes McKinney questo dovrebbe essere 'resample' in 0.8, non è vero? – bmu

+0

Se aggiorni la tua risposta, la accetterei. altrimenti dovresti rimuoverlo, perché indirizzerà gli utenti nella direzione sbagliata. – bmu