web-dev-qa-db-fra.com

Réindexation pandas séries temporelles du type d'objet au type de date / heure

J'ai une série chronologique qui n'est pas reconnue comme un DatetimeIndex malgré son indexation par des chaînes standard AAAA-MM-JJ avec des dates valides. Les contraindre à un DatetimeIndex valide semble être assez inélégant pour me faire penser que je fais quelque chose de mal.

J'ai lu des données (formatées paresseusement par quelqu'un d'autre) qui contiennent des valeurs datetime invalides et je supprime ces observations invalides.

In [1]: df = pd.read_csv('data.csv',index_col=0)
In [2]: print df['2008-02-27':'2008-03-02']
Out[2]: 
             count
2008-02-27  20
2008-02-28   0
2008-02-29  27
2008-02-30   0
2008-02-31   0
2008-03-01   0
2008-03-02  17

In [3]: def clean_timestamps(df):
    # remove invalid dates like '2008-02-30' and '2009-04-31'
    to_drop = list()
    for d in df.index:
        try:
            datetime.date(int(d[0:4]),int(d[5:7]),int(d[8:10]))
        except ValueError:
            to_drop.append(d)
    df2 = df.drop(to_drop,axis=0)
    return df2

In [4]: df2 = clean_timestamps(df)
In [5] :print df2['2008-02-27':'2008-03-02']
Out[5]:
             count
2008-02-27  20
2008-02-28   0
2008-02-29  27
2008-03-01   0
2008-03-02  17

Ce nouvel index n'est toujours reconnu que comme un type d'objet plutôt que comme DatetimeIndex.

In [6]: df2.index
Out[6]: Index([2008-01-01, 2008-01-02, 2008-01-03, ..., 2012-11-27, 2012-11-28,
   2012-11-29], dtype=object)

La réindexation produit des NaN car ce sont des dtypes différents.

In [7]: i = pd.date_range(start=min(df2.index),end=max(df2.index))
In [8]: df3 = df2.reindex(index=i,columns=['count'])
In [9]: df3['2008-02-27':'2008-03-02']
Out[9]: 
            count
2008-02-27 NaN
2008-02-28 NaN
2008-02-29 NaN
2008-03-01 NaN
2008-03-02 NaN

Je crée un nouveau cadre de données avec l'index approprié, je dépose les données dans un dictionnaire, puis je remplis le nouveau cadre de données en fonction des valeurs du dictionnaire (en sautant les valeurs manquantes).

In [10]: df3 = pd.DataFrame(columns=['count'],index=i)
In [11]: values = dict(df2['count'])
In [12]: for d in i:
    try:
        df3.set_value(index=d,col='count',value=values[d.isoformat()[0:10]])
    except KeyError:
        pass
In [13]: print df3['2008-02-27':'2008-03-02']
Out[13]: 

             count
2008-02-27  20
2008-02-28   0
2008-02-29  27
2008-03-01   0
2008-03-02  17

In [14]: df3.index
Out[14];
<class 'pandas.tseries.index.DatetimeIndex'>
[2008-01-01 00:00:00, ..., 2012-11-29 00:00:00]
Length: 1795, Freq: D, Timezone: None

Cette dernière partie de la définition de valeurs basées sur des recherches dans un dictionnaire saisi par des chaînes semble particulièrement hacky et me fait penser que j'ai raté quelque chose d'important.

29
Brian Keegan

Vous pouvez utiliser pd.to_datetime:

In [1]: import pandas as pd

In [2]: pd.to_datetime('2008-02-27')
Out[2]: datetime.datetime(2008, 2, 27, 0, 0)

Cela vous permet de "nettoyer" l'index (ou de manière similaire une colonne) en l'appliquant à la série:

df.index = pd.to_datetime(df.index)

ou

df['date_col'] = df['date_col'].apply(pd.to_datetime)
45
Andy Hayden