¿Pueden los pandas reconocer automáticamente las fechas?

Hoy me sorprendió positivamente el hecho de que, al leer datos de un archivo de datos (por ejemplo), los pandas pueden reconocer tipos de valores:

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3']) 

Por ejemplo, se puede comprobar de esta manera:

 for i, r in df.iterrows(): print type(r['col1']), type(r['col2']), type(r['col3']) 

En particular, los enteros, flotadores y cadenas fueron reconocidos correctamente. Sin embargo, tengo una columna que tiene fechas en el siguiente formato: 2013-6-4 . Estas fechas se reconocieron como cadenas (no como objetos de fecha de python). ¿Hay una manera de “aprender” pandas a fechas reconocidas?

Debes agregar parse_dates=True , o parse_dates=['column name'] al leer, eso suele ser suficiente para analizarlo mágicamente. Pero siempre hay formatos extraños que necesitan ser definidos manualmente. En tal caso, también puede agregar una función de analizador de fechas, que es la forma más flexible posible.

Supongamos que tiene una columna ‘datetime’ con su cadena, entonces:

 dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S') df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse) 

De esta manera, incluso puede combinar varias columnas en una sola columna de fecha y hora, esto combina una columna de “fecha” y una “hora” en una sola columna de “fecha y hora”:

 dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S') df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse) 

Puede encontrar directivas (es decir, las letras que se usarán para diferentes formatos) para strptime y strftime en esta página .

Quizás la interfaz de pandas haya cambiado desde que contestó @Rutger, pero en la versión que estoy usando (0.15.2), la función date_parser recibe una lista de fechas en lugar de un solo valor. En este caso, su código debería actualizarse así:

 dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates] df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse) 

El método pandas read_csv es ideal para analizar fechas. Documentación completa en http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

Incluso puede tener las diferentes partes de fecha en diferentes columnas y pasar el parámetro:

 parse_dates : boolean, list of ints or names, list of lists, or dict If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date column. {'foo' : [1, 3]} -> parse columns 1, 3 as date and call result 'foo' 

La detección predeterminada de fechas funciona muy bien, pero parece estar sesgada hacia los formatos de fecha norteamericanos. Si vives en otro lugar, es posible que te sorprendan los resultados. Hasta donde puedo recordar, el 1/6/2000 significa el 6 de enero en los EE. UU. En lugar del 1 de junio donde vivo. Es lo suficientemente inteligente como para hacerlos girar si se usan fechas como 23/6/2000. Sin embargo, es probable que sea más seguro quedarse con las variaciones de fecha YYYYMMDD. Disculpas a los desarrolladores de pandas, pero no lo he probado recientemente con fechas locales.

puede usar el parámetro date_parser para pasar una función para convertir su formato.

 date_parser : function Function to use for converting a sequence of string columns to an array of datetime instances. The default uses dateutil.parser.parser to do the conversion. 

Al fusionar dos columnas en una sola columna de fecha y hora, la respuesta aceptada genera un error (pandas versión 0.20.3), ya que las columnas se envían a la función date_parser por separado.

Los siguientes trabajos:

 def dateparse(d,t): dt = d + " " + t return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S') df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse) 

Sí, de acuerdo con la documentación de pandas.read_csv :

Nota: existe una ruta rápida para las fechas con formato iso8601 .

Entonces, si su csv tiene una columna llamada datetime y las fechas se parecen a 2013-01-01T01:01 por ejemplo, ejecutar esto hará que los pandas (estoy en v0.19.2) recojan la fecha y la hora automáticamente:

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Tenga en cuenta que necesita pasar explícitamente las parse_dates , no funciona sin él.

Verificar con:

df.dtypes

Debería ver que el tipo de datos de la columna es datetime64[ns]

Puede usar pandas.to_datetime() como se recomienda en la documentación para pandas.read_csv() :

Si una columna o índice contiene una fecha que no se puede analizar, la columna o el índice completo se devolverán sin alterar como un tipo de datos de objeto. Para el análisis de fecha y hora no estándar, use pd.to_datetime después de pd.read_csv .

Manifestación:

 >>> D = {'date': '2013-6-4'} >>> df = pd.DataFrame(D, index=[0]) >>> df date 0 2013-6-4 >>> df.dtypes date object dtype: object >>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d') >>> df date 0 2013-06-04 >>> df.dtypes date datetime64[ns] dtype: object 

Si el rendimiento te importa, asegúrate de que tienes tiempo:

 import sys import timeit import pandas as pd print('Python %s on %s' % (sys.version, sys.platform)) print('Pandas version %s' % pd.__version__) repeat = 3 numbers = 100 def time(statement, _setup=None): print (min( timeit.Timer(statement, setup=_setup or setup).repeat( repeat, numbers))) print("Format %m/%d/%y") setup = """import pandas as pd import io data = io.StringIO('''\ ProductCode,Date ''' + '''\ x1,07/29/15 x2,07/29/15 x3,07/29/15 x4,07/30/15 x5,07/29/15 x6,07/29/15 x7,07/29/15 y7,08/05/15 x8,08/05/15 z3,08/05/15 ''' * 100)""" time('pd.read_csv(data); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"],' 'infer_datetime_format=True); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"],' 'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)') print("Format %Y-%m-%d %H:%M:%S") setup = """import pandas as pd import io data = io.StringIO('''\ ProductCode,Date ''' + '''\ x1,2016-10-15 00:00:43 x2,2016-10-15 00:00:56 x3,2016-10-15 00:00:56 x4,2016-10-15 00:00:12 x5,2016-10-15 00:00:34 x6,2016-10-15 00:00:55 x7,2016-10-15 00:00:06 y7,2016-10-15 00:00:01 x8,2016-10-15 00:00:00 z3,2016-10-15 00:00:02 ''' * 1000)""" time('pd.read_csv(data); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"],' 'infer_datetime_format=True); data.seek(0)') time('pd.read_csv(data, parse_dates=["Date"],' 'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)') 

huellas dactilares:

 Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) [Clang 6.0 (clang-600.0.57)] on darwin Pandas version 0.23.4 Format %m/%d/%y 0.19123052499999993 8.20691274 8.143124389 1.2384357139999977 Format %Y-%m-%d %H:%M:%S 0.5238807110000039 0.9202787830000005 0.9832778819999959 12.002349824999996 

Así que con la fecha formateada iso8601 ( %Y-%m-%d %H:%M:%S es aparentemente una fecha formateada iso8601, supongo que la T puede ser eliminada y reemplazada por un espacio) no debe especificar infer_datetime_format ( lo que no hace la diferencia con otros más comunes, aparentemente) y pasar su propio analizador en un rendimiento inigualable. Por otro lado, date_parser hace una diferencia con formatos de día no tan estándar. Asegúrese de tiempo antes de optimizar, como de costumbre.