Come modificare il formato datetime nei panda


109

Il mio dataframe ha una DOBcolonna (formato di esempio 1/1/2016) che per impostazione predefinita viene convertita in panda dtype 'oggetto':DOB object

Conversione a questo formato della data con df['DOB'] = pd.to_datetime(df['DOB'])la data viene convertito in: 2016-01-26e il suo dtypeè il seguente: DOB datetime64[ns].

Ora voglio convertire questo formato di data in 01/26/2016o in qualsiasi altro formato di data generale. Come lo faccio?

Qualunque sia il metodo che provo, mostra sempre la data in 2016-01-26formato.


Stai cercando una soluzione che funzioni solo con notebook Jupyter? (in tal caso usa uno 'styler' per colonna) o funziona in una normale console Python e iPython?
smci

Risposte:


209

Puoi usare dt.strftimese hai bisogno di convertire datetimein altri formati (ma nota che allora dtypedella colonna sarà 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

32
'strftime' converte la colonna datetime in unicode per applicare l'operazione su DOB1, dobbiamo nuovamente convertirla in datetime. Non esiste un altro modo per formattare senza perdere data_type?
M. Zaman

@jezrael, esiste una soluzione migliore che mantenga anche il tipo di dati e non restituisca le date a una colonna dell'oggetto? Il problema è che se provi a convertirlo dopo la riga 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')' come suggerito alla soluzione sopra quindi le date tornano al loro formato originale.
Outcast

haha, quindi come posso farlo se voglio usare questa colonna per una .mergecolonna datetime di un altro dataframe? Ha senso convertire l'altra colonna datetime in una colonna oggetto per eseguire l'operazione .merge?
Outcast

Sì, a quanto pare sono d'accordo, ma con "Non esiste :(" mi hai detto che non posso convertire la colonna in datetime dopo aver cambiato il suo formato senza perdere il suo nuovo formato. Quindi?
Outcast

Ok, per quanto ho capito, .mergepuò ancora essere fatto correttamente se entrambe le colonne sono colonne datetimes anche se non hanno lo stesso identico formato. È giusto?
Outcast

21

Modifica del formato ma non modifica del tipo:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))

ricorda solo che df ["date"] dovrebbe essere datetime64 prima di farlo
adhg

4
No! Supponiamo che il valore originale di alcuni elementi nella datecolonna sia " 26 novembre 2019". strftime()significa "stringa dal tempo" , quindi df["date"].dt.strftime('%Y-%m')sarà una stringa "2019-11" per quell'elemento. Poi, pd.to_datetime()permette di convertire questa stringa di nuovo al datetime64formato, ma ora come “November 1 , 2019”! Quindi il risultato sarà: Nessun cambio di formato, ma il cambio del valore della data stesso!
MarianD

2
@MarianD: tutti i tuoi commenti sulle singole risposte sono utili, ma puoi riassumerli in un elenco di "Trappole / Non farlo" in fondo alla tua risposta? Inoltre è necessario indicare chiaramente qual è il problema con ciascuno di questi: se una qualsiasi delle date di input non è nel formato previsto, rischierà di generare eccezioni o di alterare la data. Scrivendo semplicemente "No!" ovunque non lo trasmette.
smci

8

Il codice seguente ha funzionato per me invece del precedente: provalo!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')

2
No! Il tuo format='%m/%d/%Y'parametro è per analizzare una stringa, cioè dovresti fornire la stringa in tale formato (ad esempio "5/13/2019"). Niente di più, nessun cambio di formato. Sarà ancora visualizzato come 2019-05-13- o solleverà un'eccezione, se df['DOB'].astype(str)contiene elementi non in tale formato, ad esempio in un formato "2019-05-13".
MarianD

4

Rispetto alla prima risposta, consiglierò di utilizzare prima dt.strftime (), quindi pd.to_datetime (). In questo modo, risulterà comunque nel tipo di dati datetime.

Per esempio,

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)

2
Questo non funziona almeno nel mio caso. In particolare, la colonna viene convertita nel tipo di dati datetime ma anche i valori vengono convertiti nel formato originale!
Outcast

No! Errore di sintassi (parentesi graffa mancante), nella mia versione di Pandas (0.25.1) un altro errore di sintassi (dt.strftime () - può usare solo l'accessor .dt con valori datetimelike) - ti affidi al tipo di dati intrinseco, ma in diverse versioni di Panda i tipi di dati intrinseci possono essere diversi) e una logica strana: perché convertire datetime in stringa e poi di nuovo in datetime ? Vedi il mio commento alla risposta di rishi jain.
MarianD,

2

C'è una differenza tra

  • il contenuto di una cella del dataframe (un valore binario) e
  • la sua presentazione (mostrandola) per noi umani.

Quindi la domanda è: come raggiungere la presentazione appropriata dei miei dati senza modificare i dati / i tipi di dati stessi?

Ecco la risposta:

  • Se utilizzi il notebook Jupyter per visualizzare il tuo dataframe, o
  • se vuoi raggiungere una presentazione sotto forma di un file HTML (anche con molti superflui preparati ide classattributi per ulteriori stili CSS - puoi o non puoi usarli),

usa lo styling . Lo stile non modifica i dati / tipi di dati delle colonne del tuo dataframe.

Ora ti mostro come raggiungerlo nel taccuino Jupyter - per una presentazione sotto forma di file HTML vedi la nota vicino alla fine della domanda.

Suppongo che la tua colonna DOB abbia già il tipodatetime64 (hai dimostrato di sapere come raggiungerlo). Ho preparato un semplice dataframe (con una sola colonna) per mostrarti alcuni stili di base:

  • Non in stile:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Lo stile come 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
  • Lo stile come 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

Stai attento!
L'oggetto restituito NON è un dataframe - è un oggetto della classe Styler, quindi non assegnarlo di nuovo a df:

Non farlo:

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

(Ogni dataframe ha il suo oggetto Styler accessibile dalla sua .styleproprietà e abbiamo modificato questo df.styleoggetto, non il dataframe stesso.)


Domande e risposte:

  • D: Perché il tuo oggetto Styler (o un'espressione che lo restituisce) utilizzato come ultimo comando in una cella del taccuino Jupyter visualizza la tua tabella (con stile) e non l'oggetto Styler stesso?

  • R: Perché ogni oggetto Styler ha un metodo di callback ._repr_html_()che restituisce un codice HTML per il rendering del dataframe (come una bella tabella HTML).

    Jupyter Notebook IDE chiama automaticamente questo metodo per eseguire il rendering degli oggetti che lo hanno.


Nota:

Non hai bisogno del notebook Jupyter per lo stile (cioè per un bel output di un dataframe senza cambiare i suoi dati / tipi di dati ).

Un oggetto Styler ha anche un metodo render(), se vuoi ottenere una stringa con il codice HTML (ad es. Per pubblicare il tuo dataframe formattato sul Web, o semplicemente presentare la tua tabella in formato HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()

Vale la pena sottolineare che il codice dello styler come questo è concepito per essere eseguito sotto, e ha effetto solo su notebook Jupyter, e ha assolutamente effetto zero se eseguito in console o iPython . L'OP non ha specificato "sotto Jupyter", quindi questa potrebbe o non potrebbe essere una soluzione praticabile a seconda della loro configurazione. Un sacco di codice di data science viene copiato e incollato e i presupposti specifici di Jupyter non vengono specificati esplicitamente, quindi le persone si chiedono perché il codice dello styler "non funziona" quando viene eseguito nel loro ambiente (console).
smci

@smci, non è esplicitamente menzionato nel secondo paragrafo della mia risposta? Sotto forma di condizionale if, dichiarazione così conosciuta per ogni programmatore? - Nonostante ciò, grazie per il tuo commento, potrebbe essere utile per alcune persone.
MarianD

no, è molto poco chiaro, anche seppellito. La domanda originale non supponeva nulla su Jupyter, e l'OP e alcuni utenti potrebbero non avere nemmeno Jupyter a loro disposizione. La tua risposta dovrebbe dire in grassetto la prima riga "Il seguente approccio (stile) funziona solo con il notebook Jupyter e non avrà alcun effetto se eseguito al di fuori del notebook Jupyter" . (Nei blog e nei siti di data science vedo quotidianamente persone che pubblicano codice Jupyter in ambienti non Jupyter e si chiedono perché non funziona).
smci

Freddo. Ti suggerisco anche di aggiungere tutte le (molte) insidie ​​che hai identificato negli altri approcci "convert-to-string-with-strftime-then-back-again-with-pd.to_datetime". Almeno, è necessario menzionare la raccolta e la cattura delle eccezioni. Inoltre, pd.to_datetime()ha gli argomenti errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactper controllare quanto sia preciso e felice rispetto alle eccezioni e se gli output non validi vengono obbligati NaTo cosa. Ciò che lo rende più complicato nei set di dati "del mondo reale" sono formati, orari, fusi orari misti / mancanti / incompleti; le eccezioni non sono necessariamente cose negative.
smci

... oppure posso scriverlo come un insieme di insidie ​​negli approcci non Jupyter.
smci

1

Di seguito il codice cambia in tipo "datetime" e si formatta anche nella stringa di formato data. Funziona bene!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))

2
cambiarlo in questo:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe

No! - Perché convertire datetime in stringa e poi di nuovo in datetime ? Vedi i miei commenti ad altre risposte.
MarianD

1

Puoi provare questo convertirà il formato della data in GG-MM-AAAA:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)

No! dayfirst=Trueè solo la specifica di un ordine di analisi della data, ad esempio quella stringa di data ambivalente come "2-1-2019" verrà analizzata come 2 gennaio 2019 e non come 1 febbraio 2019. Niente di più, nessuna modifica per la formattazione dell'output .
MarianD
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.