Cómo cambiar el formato de fecha y hora en pandas

109

Mi marco de datos tiene un DOB columna (formato de ejemplo 1/1/2016) que de forma predeterminada se convierte en pandas dtype 'object':DOB object

Al convertir esto a formato de fecha con df['DOB'] = pd.to_datetime(df['DOB']), la fecha se convierte a: 2016-01-26y sudtype es: DOB datetime64[ns].

Ahora quiero convertir este formato de fecha a 01/26/2016 en cualquier otro formato de fecha general. ¿Cómo lo hago?

Cualquiera que sea el método que intento, siempre muestra la fecha en 2016-01-26formato.

yo me
fuente
¿Está buscando una solución que solo funcione con el portátil Jupyter? (en cuyo caso use un 'styler' por columna) o funciona en una consola Python simple e iPython?
smci

Respuestas:

209

Puede usar dt.strftimesi necesita convertir datetimea otros formatos (pero tenga en cuenta que la dtypecolumna será object( string)):

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016', 1: '26/1/2016'}})
print (df)
         DOB
0  26/1/2016 
1  26/1/2016

df['DOB'] = pd.to_datetime(df.DOB)
print (df)
         DOB
0 2016-01-26
1 2016-01-26

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print (df)
         DOB        DOB1
0 2016-01-26  01/26/2016
1 2016-01-26  01/26/2016
Jezrael
fuente
32
'strftime' convierte la columna de fecha y hora a unicode para aplicar la operación en DOB1, nuevamente tenemos que convertirla a fecha y hora. ¿No hay otra forma de formatear sin perder el data_type?
M.Zaman
@jezrael, ¿hay alguna solución mejor que conserve también el tipo de datos y no devuelva las fechas a una columna de objeto? El problema es que si intenta convertirlo después de la línea 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')' como se sugiere en la solución arriba, las fechas vuelven a su formato original.
Paria
jaja, entonces, ¿cómo puedo hacer esto si quiero usar esta columna para una .mergecolumna de fecha y hora de otro marco de datos? ¿Tiene algún sentido convertir la otra columna de fecha y hora en una columna de objeto para hacer el .merge?
Paria
Sí, aparentemente estoy de acuerdo, pero con "No existe :(" me dijiste que no puedo convertir la columna a fecha y hora después de cambiar su formato sin perder su nuevo formato. ¿Entonces?
Outcast
Ok, por lo que tengo entendido, .mergeaún se puede hacer correctamente si ambas columnas son columnas de fecha y hora, incluso si no tienen exactamente el mismo formato. ¿Es esto correcto?
Paria
21

Cambiar el formato pero no cambiar el tipo:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Yanni Cao
fuente
solo recuerde que df ["date"] debe ser datetime64 antes de hacer esto
adhg
4
¡No! Suponga que el valor original de algún elemento de la datecolumna es " 26 de noviembre de 2019". strftime()significa "cadena de tiempo" , por df["date"].dt.strftime('%Y-%m')lo que será una cadena "2019-11" para ese elemento. Luego, pd.to_datetime()convertirá esta cadena de nuevo al datetime64formato, ¡pero ahora como " 1 de noviembre de 2019"! Entonces, el resultado será: ¡ Sin cambio de formato, pero sí el cambio del valor de la fecha!
MarianD
2
@MarianD: todos sus comentarios sobre respuestas individuales son útiles, pero ¿podría resumirlos en un resumen de "Errores / No hacer esto" al final de su respuesta? Además, debe indicar claramente cuál es el problema con cada uno de estos: si alguna de las fechas de entrada no está en el formato esperado, correrá el riesgo de arrojar excepciones o alterar la fecha. Simplemente escribiendo "¡No!" en todas partes no transmite eso.
smci
8

El siguiente código funcionó para mí en lugar del anterior, ¡pruébalo!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')
rishi jain
fuente
2
¡No! Su format='%m/%d/%Y'parámetro es para analizar una cadena, es decir, se supone que debe proporcionar la cadena en tal formato (por ejemplo "5/13/2019"). Nada más, ningún cambio de formato. Seguirá mostrándose como 2019-05-13- o generará una excepción, si df['DOB'].astype(str)contiene elementos que no están en ese formato, por ejemplo, en un formato "2019-05-13".
MarianD
4

En comparación con la primera respuesta, recomendaré usar primero dt.strftime (), luego pd.to_datetime (). De esta manera, seguirá dando como resultado el tipo de datos de fecha y hora.

Por ejemplo,

import pandas as pd

df = pd.DataFrame({'DOB': {0: '26/1/2016 ', 1: '26/1/2016 '})
print(df.dtypes)

df['DOB1'] = df['DOB'].dt.strftime('%m/%d/%Y')
print(df.dtypes)

df['DOB1'] = pd.to_datetime(df['DOB1'])
print(df.dtypes)
user3512680
fuente
2
Esto no funciona al menos en mi caso. Específicamente, la columna se convierte al tipo de datos de fecha y hora, ¡pero también los valores se convierten al formato original!
Paria
¡No! Error de sintaxis (llave faltante), en mi versión de Pandas (0.25.1) otro error de sintaxis (dt.strftime () - solo puede usar el descriptor de acceso .dt con valores de fecha y hora) - usted confía en el tipo de datos inherente, pero en diferentes versiones de Pandas, los tipos de datos inherentes pueden ser diferentes) y una lógica extraña: ¿por qué convertir la fecha y hora en una cadena y luego volver a la fecha y hora ? Vea mi comentario a la respuesta de rishi jain.
MarianD
2

Hay una diferencia entre

  • el contenido de una celda de marco de datos (un valor binario) y
  • su presentación (mostrándola) para nosotros, los humanos.

Entonces, la pregunta es: ¿Cómo lograr la presentación adecuada de mis datos sin cambiar los datos / tipos de datos en sí mismos?

Esta es la respuesta:

  • Si usa el cuaderno Jupyter para mostrar su marco de datos, o
  • si se quiere llegar a una presentación en forma de un archivo HTML (incluso con muchos preparados superflua idy classatributos para más estilo CSS - que puede o no puede usarlos),

usar estilo . El estilo no cambia los datos / tipos de datos de las columnas de su marco de datos.

Ahora le muestro cómo llegar a él en el cuaderno de Jupyter; para una presentación en forma de archivo HTML, vea la nota cerca del final de la pregunta.

Supongo que tu columna DOB ya tiene el tipodatetime64 (has demostrado que sabes cómo llegar). Preparé un marco de datos simple (con solo una columna) para mostrarte algunos estilos básicos:

  • Sin estilo:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Diseñándolo como mm/dd/yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
          DOB
0  07/03/2019
1  08/03/2019
2  09/03/2019
3  10/03/2019
  • Diseñándolo como dd-mm-yyyy:

       df.style.format({"DOB": lambda t: t.strftime("%d-%m-%Y")}) 
          DOB
0  03-07-2019
1  03-08-2019
2  03-09-2019
3  03-10-2019

¡Ten cuidado!
El objeto que regresa NO es un marco de datos, es un objeto de la clase Styler, así que no lo asigne de nuevo a df:

No hagas esto:

df = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})    # Don´t do this!

(Cada marco de datos tiene su objeto Styler accesible por su .stylepropiedad, y cambiamos este df.styleobjeto, no el marco de datos en sí).


Preguntas y respuestas:

  • P: ¿Por qué su objeto Styler (o una expresión que lo devuelve) utilizado como último comando en una celda de cuaderno de Jupyter muestra su tabla (con estilo) y no el objeto Styler en sí?

  • R: Porque cada objeto Styler tiene un método de devolución de llamada ._repr_html_()que devuelve un código HTML para representar su marco de datos (como una bonita tabla HTML).

    Jupyter Notebook IDE llama a este método automáticamente para representar los objetos que lo tienen.


Nota:

No necesita el cuaderno Jupyter para diseñar (es decir, para generar una buena salida de un marco de datos sin cambiar sus datos / tipos de datos ).

Un objeto Styler también tiene un método render(), si desea obtener una cadena con el código HTML (por ejemplo, para publicar su marco de datos formateado en la Web, o simplemente presentar su tabla en formato HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
MarianD
fuente
Vale la pena señalar que el código de styler como este está diseñado para ejecutarse bajo, y solo tiene efecto en el portátil Jupyter, y tiene un efecto absolutamente nulo cuando se ejecuta en la consola o iPython . El OP no especificó "bajo Jupyter", por lo que esta puede o no ser una solución viable dependiendo de su configuración. Una gran cantidad de código de ciencia de datos se copia y pega, y las suposiciones específicas de Jupyter no se especifican explícitamente, entonces la gente se pregunta por qué el código de estilo "no funciona" cuando se ejecuta en su entorno (de consola).
smci
@smci, ¿no se menciona explícitamente en el segundo párrafo de mi respuesta? ¿En forma de condicional if, declaración tan conocida para todos los programadores? - A pesar de ello gracias por tu comentario, puede ser de ayuda para algunas personas.
MarianD
no, eso es muy poco claro, también enterrado. La pregunta original no supuso nada sobre Jupyter, y es posible que el OP y algunos usuarios ni siquiera tengan Jupyter disponible. Su respuesta tendría que decir en negrita su primera línea "El siguiente enfoque (estilo) solo funciona en el cuaderno Jupyter y no tendrá ningún efecto cuando se ejecute fuera del cuaderno Jupyter" . (En blogs y sitios de ciencia de datos, veo a diario a personas que publican código de Jupyter en entornos que no son de Jupyter y se preguntan por qué no funciona).
smci
Frio. También le sugiero que agregue todas las (muchas) trampas que identificó en los otros enfoques "convertir-a-cadena-con-strftime-luego-volver-con-pd.to_datetime". Al menos, es necesario mencionar las excepciones de levantamiento y captura. Además, pd.to_datetime()tiene los argumentos errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactpara controlar qué tan preciso y feliz es con las excepciones, y si las salidas no válidas se obligan a hacerlo NaTo qué. Lo que lo hace más complicado en los conjuntos de datos del "mundo real" son los formatos, horas, zonas horarias, etc. mezclados / faltantes / incompletos; las excepciones no son necesariamente cosas malas.
smci
... o de lo contrario puedo escribir eso como un resumen de las trampas en los enfoques que no son de Jupyter.
smci
1

El siguiente código cambia al tipo 'datetime' y también a los formatos en la cadena de formato dada. ¡Funciona bien!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))
San
fuente
2
cámbielo a esto:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe
¡No! - ¿Por qué convertir datetime a string y luego volver a datetime ? Vea mis comentarios a otras respuestas.
MarianD
1

Puede probar esto, convertirá el formato de fecha a DD-MM-YYYY:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
fuente
¡No! dayfirst=Truees solo la especificación de un orden de análisis de fecha, por ejemplo, esa cadena de fecha ambivalente como "2-1-2019" se analizará como 2 de enero de 2019, y no como 1 de febrero de 2019. Nada más, no hay cambios para el formato de salida .
MarianD