web-dev-qa-db-fra.com

Comment convertir une chaîne en date/heure avec nulls - python, pandas?

J'ai une série avec des dates/heures (en tant que chaînes) et des valeurs nuls en tant que "nan":

import pandas as pd, numpy as np, datetime as dt
df = pd.DataFrame({'Date':['2014-10-20 10:44:31', '2014-10-23 09:33:46', 'nan', '2014-10-01 09:38:45']})

J'essaie de les convertir en date/heure:

df['Date'] = df['Date'].apply(lambda x: dt.datetime.strptime(x, '%Y-%m-%d %H:%M:%S'))

mais j'obtiens l'erreur:

time data 'nan' does not match format '%Y-%m-%d %H:%M:%S'

J'essaie donc de transformer ces valeurs en valeurs nulles réelles:

df.ix[df['Date'] == 'nan', 'Date'] = np.NaN

et répétez:

df['Date'] = df['Date'].apply(lambda x: dt.datetime.strptime(x, '%Y-%m-%d %H:%M:%S'))

mais alors j'obtiens l'erreur:

doit être string, pas float

Quel est le moyen le plus rapide de résoudre ce problème?

10
Colin O'Brien

Utilisez simplement to_datetime et configurez errors='coerce' pour gérer les données dupliquées:

In [321]:

df['Date'] = pd.to_datetime(df['Date'], errors='coerce')
df
Out[321]:
                 Date
0 2014-10-20 10:44:31
1 2014-10-23 09:33:46
2                 NaT
3 2014-10-01 09:38:45

In [322]:

df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4 entries, 0 to 3
Data columns (total 1 columns):
Date    3 non-null datetime64[ns]
dtypes: datetime64[ns](1)
memory usage: 64.0 bytes

le problème avec l'appel de strptime est que cela générera une erreur si la chaîne, ou le type, est incorrect.

Si vous faisiez cela, alors ça marcherait:

In [324]:

def func(x):
    try:
        return dt.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
    except:
        return pd.NaT

df['Date'].apply(func)
Out[324]:
0   2014-10-20 10:44:31
1   2014-10-23 09:33:46
2                   NaT
3   2014-10-01 09:38:45
Name: Date, dtype: datetime64[ns]

mais il sera plus rapide d’utiliser le to_datetime incorporé plutôt que d’appeler apply qui consiste essentiellement à boucler votre série.

timings

In [326]:

%timeit pd.to_datetime(df['Date'], errors='coerce')
%timeit df['Date'].apply(func)
10000 loops, best of 3: 65.8 µs per loop
10000 loops, best of 3: 186 µs per loop

Nous voyons ici que l'utilisation de to_datetime est 3X plus rapide.

20
EdChum

Je trouve que laisser les pandas faire le travail est trop lent sur de grandes trames de données. Dans un autre article, j'ai découvert une technique qui accélère considérablement cette opération lorsque le nombre de valeurs uniques est beaucoup plus petit que le nombre de lignes. (Mes données sont généralement des données de cours ou de commerce.) Il commence par créer un dict qui mappe les dates de texte sur leurs objets datetime, puis applique le dict pour convertir la colonne de dates de texte.

def str2time(val):
    try:
        return dt.datetime.strptime(val, '%H:%M:%S.%f')
    except:
        return pd.NaT

def TextTime2Time(s):
    times = {t : str2time(t) for t in s.unique()}
    return s.apply(lambda v: times[v])

df.date = TextTime2Time(df.date)
0
jdmarino