Pandas: conversión de fecha lenta

Estoy leyendo un CSV enorme con un campo de fecha en el formato YYYYMMDD y estoy usando el siguiente lambda para convertirlo al leer:

 import pandas as pd df = pd.read_csv(filen, index_col=None, header=None, parse_dates=[0], date_parser=lambda t:pd.to_datetime(str(t), format='%Y%m%d', coerce=True)) 

Sin embargo, esta función es muy lenta.

¿Alguna sugerencia para mejorarla?

Intente usar esta función para analizar las fechas:

 def lookup(s): """ This is an extremely fast approach to datetime parsing. For large data, the same dates are often repeated. Rather than re-parse these, we store all unique dates, parse them, and use a lookup to convert all dates. """ dates = {date:pd.to_datetime(date) for date in s.unique()} return s.map(dates) 

Utilízalo como:

 df['date-column'] = lookup(df['date-column']) 

Puntos de referencia:

 $ python date-parse.py to_datetime: 5799 ms dateutil: 5162 ms strptime: 1651 ms manual: 242 ms lookup: 32 ms 

Fuente: https://github.com/sanand0/benchmarks/tree/master/date-parse

Gran sugerencia @EdChum! Como sugiere @EdChum, el uso de infer_datetime_format=True puede ser significativamente más rápido. A continuación se muestra mi ejemplo.

Tengo un archivo de datos de temperatura de un registro de sensores, que se parece a esto:

 RecNum,Date,LocationID,Unused 1,11/7/2013 20:53:01,13.60,"117","1", 2,11/7/2013 21:08:01,13.60,"117","1", 3,11/7/2013 21:23:01,13.60,"117","1", 4,11/7/2013 21:38:01,13.60,"117","1", ... 

Mi código lee el csv y analiza la fecha ( parse_dates=['Date'] ). Con infer_datetime_format=False , toma 8min 8sec :

 Tue Jan 24 12:18:27 2017 - Loading the Temperature data file. Tue Jan 24 12:18:27 2017 - Temperature file is 88.172 MB. Tue Jan 24 12:18:27 2017 - Loading into memory. Please be patient. Tue Jan 24 12:26:35 2017 - Success: loaded 2,169,903 records. 

Con infer_datetime_format=True , se necesitan 13 segundos :

 Tue Jan 24 13:19:58 2017 - Loading the Temperature data file. Tue Jan 24 13:19:58 2017 - Temperature file is 88.172 MB. Tue Jan 24 13:19:58 2017 - Loading into memory. Please be patient. Tue Jan 24 13:20:11 2017 - Success: loaded 2,169,903 records. 

Análisis de fecha simplificado con almacenamiento en caché

Leer todos los datos y luego convertirlos siempre será más lento que convertirlos mientras se lee el CSV. Ya que no tendrá que repetir dos veces todos los datos si lo hace de inmediato. Tampoco tiene que almacenarlo como cadenas en la memoria.

Podemos definir nuestro propio analizador de fechas que utiliza un caché para las fechas que ya ha visto.

 import pandas as pd cache = {} def cached_date_parser(s): if s in cache: return cache[s] dt = pd.to_datetime(s, format='%Y%m%d', coerce=True) cache[s] = dt return dt df = pd.read_csv(filen, index_col=None, header=None, parse_dates=[0], date_parser=cached_date_parser) 

Tiene las mismas ventajas que la respuesta de @fixxxer con solo analizar cada cadena una vez, con la ventaja adicional adicional de no tener que leer todos los datos y ENTONCES analizarla. Guardando tu memoria y tiempo de procesamiento.

Prueba la biblioteca estándar:

 import datetime parser = lambda t: datetime.datetime.strptime(str(t), "%Y%m%d") 

Sin embargo, realmente no sé si esto es mucho más rápido que los pandas.

Ya que tu formato es tan simple, que tal

 def parse(t): string_ = str(t) return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:])) 

EDITAR dice que necesita hacerse cargo de los datos no válidos.

 def parse(t): string_ = str(t) try: return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:])) except: return default_datetime #you should define that somewhere else 

En general, estoy un poco en conflicto con la validez de su problema:

  • Necesita ser rápido, pero aún así obtiene sus datos de un CSV
  • Necesitas ser rápido, pero aún debes tratar con datos no válidos

Eso es un poco contradictorio; Mi enfoque personal aquí sería asumir que su “enorme” CSV solo necesita ser llevado a un formato de mejor desempeño una vez, y no debería preocuparse por la velocidad de ese proceso de conversión (porque solo ocurre una vez) o probablemente debería Traiga lo que produzca el CSV para brindarle mejores datos: hay tantos formatos que no dependen del análisis de cadenas.

No es necesario especificar un date_parser , pandas puede analizar esto sin ningún problema, y ​​será mucho más rápido:

 In [21]: import io import pandas as pd t="""date,val 20120608,12321 20130608,12321 20140308,12321""" df = pd.read_csv(io.StringIO(t), parse_dates=[0]) df.info()  Int64Index: 3 entries, 0 to 2 Data columns (total 2 columns): date 3 non-null datetime64[ns] val 3 non-null int64 dtypes: datetime64[ns](1), int64(1) memory usage: 72.0 bytes In [22]: df Out[22]: date val 0 2012-06-08 12321 1 2013-06-08 12321 2 2014-03-08 12321 

Si su fecha y hora tiene marca de tiempo UTC y solo necesita parte de ella. Conviértalo en una cadena, divida lo que necesita y luego aplique lo siguiente para un acceso mucho más rápido.

 created_at 2018-01-31 15:15:08 UTC 2018-01-31 15:16:02 UTC 2018-01-31 15:27:10 UTC 2018-02-01 07:05:55 UTC 2018-02-01 08:50:14 UTC df["date"]= df["created_at"].apply(lambda x: str(x)[:10]) df["date"] = pd.to_datetime(df["date"])