43 votes

Comment ré-échantillonner un dataframe avec différentes fonctions appliquées à chaque colonne ?

J'ai une série temporelle avec la température et le rayonnement dans un fichier pandas. dataframe . La résolution du temps est de 1 minute par pas réguliers.

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)

Comment puis-je réduire l'échantillonnage de ce dataframe à une résolution d'une heure, en calculant le taux horaire moyenne pour la température et l'heure somme pour les radiations ?

70voto

bmu Points 7109

Avec la version 0.18 de pandas, l'API de rééchantillonnage a été modifiée (voir la section docs ). Donc pour pandas >= 0.18 la réponse est :

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

Vieille réponse :

Je réponds à ma question pour refléter les changements liés à la série chronologique dans pandas >= 0.8 (toutes les autres réponses sont périmées).

En utilisant pandas >= 0.8 la réponse est :

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

3voto

Garrett Points 5477

Vous pouvez également réduire l'échantillonnage en utilisant la fonction asof méthode de pandas.DateRange objets .

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

3voto

Wes McKinney Points 17545

Pour vous séduire, dans la version 0.8.0 de pandas (en cours de développement dans le cadre de l'initiative de développement durable de l'Union européenne), il n'y a pas d'autre solution. timeseries sur GitHub), vous serez en mesure de le faire :

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

Les méthodes mentionnées ci-dessus constituent la bonne stratégie avec la version de production actuelle de pandas.

1voto

diliop Points 3208

Vous devez utiliser groupby comme tel :

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

avec comme résultat :

        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

Donc, en substance, je divise sur la valeur de l'heure et ensuite je calcule la moyenne de tamb et la somme de radiation et en renvoyant le DataFrame (approche similaire à celle de R ddply ). Pour plus d'informations, je consulterais la page de documentation de groupe par ainsi que este blog post.

Edit : Pour améliorer un peu cette échelle, vous pourriez regrouper le jour et l'heure comme tels :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X