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?
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.
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)