2013-06-18 19 views
21

Ho dati con un timestamp in UTC. Mi piacerebbe convertire il fuso orario di questo timestamp in "US/Pacific" e aggiungerlo come indice gerarchico a un DataFrame panda. Sono stato in grado di convertire il timestamp come un indice, ma perde la formattazione del fuso orario quando tento di aggiungerlo nuovamente al DataFrame, come colonna o come indice.Cambia fuso orario della colonna data-ora in panda e aggiungi come indice gerarchico

>>> import pandas as pd 
>>> dat = pd.DataFrame({'label':['a', 'a', 'a', 'b', 'b', 'b'], 'datetime':['2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00', '2011-07-19 07:00:00', '2011-07-19 08:00:00', '2011-07-19 09:00:00'], 'value':range(6)}) 
>>> dat.dtypes 
#datetime object 
#label  object 
#value  int64 
#dtype: object 

Ora se provo a convertire direttamente la serie, corro un errore.

>>> times = pd.to_datetime(dat['datetime']) 
>>> times.tz_localize('UTC') 
#Traceback (most recent call last): 
# File "<stdin>", line 1, in <module> 
# File "/Users/erikshilts/workspace/schedule-detection/python/pysched/env/lib/python2.7/site-packages/pandas/core/series.py", line 3170, in tz_localize 
# raise Exception('Cannot tz-localize non-time series') 
#Exception: Cannot tz-localize non-time series 

Se lo converto in un indice, posso manipolarlo come un archivio. Si noti che l'indice ora ha il fuso orario Pacifico.

>>> times_index = pd.Index(times) 
>>> times_index_pacific = times_index.tz_localize('UTC').tz_convert('US/Pacific') 
>>> times_index_pacific 
#<class 'pandas.tseries.index.DatetimeIndex'> 
#[2011-07-19 00:00:00, ..., 2011-07-19 02:00:00] 
#Length: 6, Freq: None, Timezone: US/Pacific 

Tuttavia, ora corro in problemi aggiungendo l'indice torna alla dataframe quanto perde la formattazione fuso orario:

>>> dat_index = dat.set_index([dat['label'], times_index_pacific]) 
>>> dat_index 
#          datetime label value 
#label              
#a  2011-07-19 07:00:00 2011-07-19 07:00:00  a  0 
#  2011-07-19 08:00:00 2011-07-19 08:00:00  a  1 
#  2011-07-19 09:00:00 2011-07-19 09:00:00  a  2 
#b  2011-07-19 07:00:00 2011-07-19 07:00:00  b  3 
#  2011-07-19 08:00:00 2011-07-19 08:00:00  b  4 
#  2011-07-19 09:00:00 2011-07-19 09:00:00  b  5 

Si noterà l'indice è tornato sul fuso orario UTC al posto del fuso orario Pacifico convertito.

Come posso modificare il fuso orario e aggiungerlo come indice a un DataFrame?

+3

Penso che questo sia un bug ... –

+2

Sì, questo è uno strano comportamento (i fusi orari sono malvagi). Probabilmente vale la pena creare [un problema] (https://github.com/pydata/pandas/issues)! –

+0

"I fusi orari sono malvagi" - distaccato. – Jason

risposta

8

Ormai è stato corretto.Ad esempio, è possibile chiamare:

dataframe.tz_localize('UTC', level=0) 

Si dovrà chiamare due volte per l'esempio dato, però. (I.e., una volta per ogni livello.)

18

Se si imposta come l'indice, questo viene automaticamente convertito in un indice:

In [11]: dat.index = pd.to_datetime(dat.pop('datetime'), utc=True) 

In [12]: dat 
Out[12]: 
        label value 
datetime 
2011-07-19 07:00:00  a  0 
2011-07-19 08:00:00  a  1 
2011-07-19 09:00:00  a  2 
2011-07-19 07:00:00  b  3 
2011-07-19 08:00:00  b  4 
2011-07-19 09:00:00  b  5 

quindi effettuare le tz_localize:

In [12]: dat.index = dat.index.tz_localize('UTC').tz_convert('US/Pacific') 

In [13]: dat 
Out[13]: 
          label value 
datetime 
2011-07-19 00:00:00-07:00  a  0 
2011-07-19 01:00:00-07:00  a  1 
2011-07-19 02:00:00-07:00  a  2 
2011-07-19 00:00:00-07:00  b  3 
2011-07-19 01:00:00-07:00  b  4 
2011-07-19 02:00:00-07:00  b  5 

e poi si può aggiungere la colonna etichetta per l'indice :

Hmmm questo è sicuramente un bug!

In [14]: dat.set_index('label', append=True).swaplevel(0, 1) 
Out[14]: 
          value 
label datetime 
a  2011-07-19 07:00:00  0 
     2011-07-19 08:00:00  1 
     2011-07-19 09:00:00  2 
b  2011-07-19 07:00:00  3 
     2011-07-19 08:00:00  4 
     2011-07-19 09:00:00  5 

Una soluzione hacky è quello di convertire il (datetime) livello direttamente (quando è già un MultiIndex):

In [15]: dat.index.levels[1] = dat.index.get_level_values(1).tz_localize('UTC').tz_convert('US/Pacific') 

In [16]: dat1 
Out[16]: 
           value 
label datetime 
a  2011-07-19 00:00:00-07:00  0 
     2011-07-19 01:00:00-07:00  1 
     2011-07-19 02:00:00-07:00  2 
b  2011-07-19 00:00:00-07:00  3 
     2011-07-19 01:00:00-07:00  4 
     2011-07-19 02:00:00-07:00  5 
+0

Ci sono due problemi che sto incontrando con questo: 1) Non riesco a chiamare tz_localize o tz_convert su un MultiIndex; 2) Accedere al campo delle ore da un singolo indice mi dà ancora l'array '[7,8,9,7,8,9]' quando vorrei i valori del Pacifico (cioè '[0, 1, 2, 0, 1, 2] '). –

+1

Mi dispiace, questo è * sicuramente * un bug (grazie per averlo trovato)! Ho aggiunto una soluzione alternativa (che è quella di convertire il livello datetime una volta che è un MultiIndex) ... –

0

La soluzione non sembra funzionare perché i livelli di indice di un indice gerarchico sembra essere immutabile (FrozenList è immutabile).

Iniziare con un indice singolare e anche l'aggiunta non funziona.

La creazione di una funzione lambda che esegue il timestamp e converte ciascun membro della serie restituito da to_datetime() non funziona.

C'è un modo per creare serie sensibili al fuso orario e quindi inserirli in un dataframe/renderli un indice?

joined_event_df = joined_event_df.set_index(['pandasTime']) 
joined_event_df.index = joined_event_df.index.get_level_values(1).tz_localize('UTC').tz_convert('US/Central') 
# we have tz-awareness above this line 
joined_event_df = joined_event_df.set_index('sequence', append = True) 
# we lose tz-awareness in the index as soon as we add another index 
joined_event_df = joined_event_df.swaplevel(0,1) 
1

Un altra soluzione che funziona in panda 0.13.1, e risolve il FrozenList non può essere assegnato problema:

index.levels = pandas.core.base.FrozenList([ 
    index.levels[0].tz_localize('UTC').tz_convert(tz), 
    index.levels[1].tz_localize('UTC').tz_convert(tz) 
]) 

Lottando molto con questo problema, MultiIndex perde tz in molte altre condizioni troppo .