Conserva solo la parte della data quando usi pandas.to_datetime


201

Uso pandas.to_datetimeper analizzare le date nei miei dati. Panda di default rappresenta le date con datetime64[ns]anche se le date sono tutte solo quotidiane. Mi chiedo se ci sia un modo elegante / intelligente per convertire le date per datetime.dateo datetime64[D]in modo tale che, quando scrivo i dati in formato CSV, le date non vengono aggiunti con 00:00:00. So di poter convertire manualmente il tipo elemento per elemento:

[dt.to_datetime().date() for dt in df.dates]

Ma questo è molto lento poiché ho molte righe e sconfigge lo scopo dell'uso pandas.to_datetime. C'è un modo per convertire dtypel'intera colonna contemporaneamente? O in alternativa, pandas.to_datetimesupporta una specifica di precisione in modo che io possa liberarmi della parte temporale mentre lavoro con i dati giornalieri?


2
Non conosco un buon modo, ma df.dates.apply(lambda x: x.date()) dovrebbe essere almeno un po 'più veloce. dai un'occhiata anche a github.com/pydata/pandas/issues/2583
root


1
Considererei queste due domande diverse. Il possibile duplicato a cui si fa riferimento mira a dividere la parte di data e ora da una colonna datetime. Questa domanda è motivata convertendo l'intera colonna in una sola volta. Immagina di avere un frame di dati con 20 colonne che rappresentano le date. Non vorrai specificare quali colonne scrivere in CSV, come suggerito nell'altra domanda.

1
Questo non è supportato in questo momento (@root punta al possibile miglioramento), qual è lo scopo di fare questo, quando si scrive su CSV?
Jeff,

3
Bene, spesso dobbiamo scrivere dati su file CSV per essere letti da altri programmi. Le 00:00:00 ridondanti rendono in generale più difficile l'elaborazione, specialmente quando lavoro con dati puramente giornalieri.

Risposte:


286

Dalla versione 0.15.0questo ora può essere fatto facilmente usando .dtper accedere solo al componente data:

df['just_date'] = df['dates'].dt.date

Quanto sopra restituisce un datetime.datedtype, se vuoi avere un datetime64allora puoi solo normalizeil componente time a mezzanotte quindi imposta tutti i valori su 00:00:00:

df['normalised_date'] = df['dates'].dt.normalize()

Ciò mantiene il tipo come datetime64ma il display mostra solo il datevalore.


33

Soluzione semplice:

df['date_only'] = df['date_time_column'].dt.date

Solo un avvertimento, questo cambia il tipo in oggetto. Quindi dovrai mantenere il tipo ('datetime64') per mantenere la coerenza.
misantroop

25

Mentre ho votato a favore della risposta di EdChum, che è la risposta più diretta alla domanda posta dall'OP, non risolve davvero il problema delle prestazioni (si basa ancora su datetimeoggetti Python , e quindi qualsiasi operazione su di essi non verrà vettorializzata, cioè sarà lento).

Un'alternativa con prestazioni migliori è quella di utilizzare df['dates'].dt.floor('d'). A rigor di termini, non "mantiene solo la parte della data", poiché imposta solo il tempo 00:00:00. Ma funziona come desiderato dall'OP quando, ad esempio:

  • stampa su schermo
  • salvataggio in csv
  • usando la colonna per groupby

... ed è molto più efficiente, poiché l'operazione è vettorializzata.

EDIT: infatti, la risposta del PO avrebbero preferito è probabilmente "le versioni recenti di pandasnon non scrivono il tempo per csv se è 00:00:00per tutte le osservazioni".


Purtroppo to_jsonscrive ancora il pieno 00:00:00.
IanS,

@IanS intendi quando usi date_format='iso'?! Di default, emette solo secondi dall'epoca.
Pietro Battiston,

Sì, questo è ciò che intendevo.
IanS,

Questo è più veloce rispetto dt.normalize()alle serie più lunghe di alcune centinaia di elementi.
C8H10N4O2,

16

Panda DatetimeIndexe Serieshanno un metodo chiamato normalizeche fa esattamente quello che vuoi.

Puoi leggere di più a riguardo in questa risposta .

Può essere usato come ser.dt.normalize()


15

Panda v0.13 +: utilizzare to_csvcon il date_formatparametro

Evita, ove possibile, di convertire le tue datetime64[ns]serie in una objectserie di datetime.dateoggetti dtype . Quest'ultimo, spesso costruito usando pd.Series.dt.date, è memorizzato come una matrice di puntatori ed è inefficiente rispetto a una serie basata su NumPy pura.

Poiché la tua preoccupazione è il formato quando scrivi su CSV , usa semplicemente il date_formatparametro di to_csv. Per esempio:

df.to_csv(filename, date_format='%Y-%m-%d')

Consulta le strftimedirettive di Python per le convenzioni di formattazione.


8

Questo è un modo semplice per estrarre la data:

import pandas as pd

d='2015-01-08 22:44:09' 
date=pd.to_datetime(d).date()
print(date)

L'OP sta già utilizzando il metodo .date () nella sua domanda, quindi questa soluzione non risponde alla sua domanda, ma ho trovato utile vedere un semplice esempio dell'uso del metodo date () solo come riferimento.
Nic Scozzaro,

5

Conversione in datetime64[D]:

df.dates.values.astype('M8[D]')

Anche se riassegnandolo a un col DataFrame lo ripristinerà a [ns].

Se volevi reale datetime.date:

dt = pd.DatetimeIndex(df.dates)
dates = np.array([datetime.date(*date_tuple) for date_tuple in zip(dt.year, dt.month, dt.day)])

3
Se si utilizza astype ('M8 [D]') trasforma i valori mancanti nella data di origine, 1970-1-1. Probabilmente è meglio usare solo pandas.to_datetime () al giorno d'oggi.
Stewbaca,

1
Nota a chiunque includa abitualmente il modulo datetime come dt, questa snipet di risposta sovrascriverà quel modulo! @Dale-Jung, forse potrebbe cambiare la linea in qualcosa come dt_index
yeliabsalohcin

Sto anche trovando un problema per cui la prossima volta che provo ad aggiungere una nuova riga tramite il df.loc[date]metodo, l'indice ritorna a un timestamp, il che significa che i successivi confronti non funzionano più
yeliabsalohcin

3

Basta dare una risposta più aggiornata nel caso in cui qualcuno veda questo vecchio post.

L'aggiunta di "utc = False" durante la conversione in datetime rimuoverà il componente del fuso orario e manterrà solo la data in un tipo di dati datetime64 [ns].

pd.to_datetime(df['Date'], utc=False)

Sarai in grado di salvarlo in Excel senza ottenere l'errore "ValueError: Excel non supporta i periodi di tempo con fusi orari. Prima di scrivere in Excel, assicurati che i fusi orari non siano consapevoli del fuso orario."

inserisci qui la descrizione dell'immagine


Questo per qualche motivo fallisce dopo aver applicato qualsiasi funzione aggregata con la colonna.
RaphX

0

Volevo essere in grado di cambiare il tipo per un set di colonne in un frame di dati e quindi rimuovere il tempo mantenendo il giorno. round (), floor (), ceil () tutto il lavoro

df[date_columns] = df[date_columns].apply(pd.to_datetime)
df[date_columns] = df[date_columns].apply(lambda t: t.dt.floor('d'))
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.