Ne conserver que la partie date lors de l'utilisation de pandas.to_datetime

202

J'utilise pandas.to_datetimepour analyser les dates dans mes données. Les pandas par défaut représentent les dates avec datetime64[ns]même si les dates sont uniquement quotidiennes. Je me demande s'il existe un moyen élégant / intelligent de convertir les dates en datetime.dateou de datetime64[D]sorte que, lorsque j'écris les données au format CSV, les dates ne soient pas ajoutées 00:00:00. Je sais que je peux convertir le type manuellement élément par élément:

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

Mais c'est vraiment lent car j'ai beaucoup de lignes et cela défait en quelque sorte le but de l'utilisation pandas.to_datetime. Existe-t-il un moyen de convertir simultanément dtypela totalité de la colonne? Ou bien, prend-il en pandas.to_datetimecharge une spécification de précision afin que je puisse me débarrasser de la partie temporelle tout en travaillant avec des données quotidiennes?

jpp
la source
2
Je ne connais pas un bon moyen, mais df.dates.apply(lambda x: x.date()) devrait être au moins un peu plus rapide. jetez également un œil à github.com/pydata/pandas/issues/2583
root
1
Je considérerais ces deux questions comme différentes. Le double possible auquel vous vous référez vise à séparer la partie date et la partie heure d'une colonne datetime. Cette question est motivée par la conversion de la colonne entière à la fois. Imaginez que vous ayez une trame de données avec 20 colonnes qui représentent des dates. Vous ne voudriez pas spécifier quelles colonnes écrire dans csv, comme suggéré dans l'autre question.
1
Ce n'est pas pris en charge pour le moment (@root indique une amélioration possible), quel est le but de le faire lors de l'écriture sur csv?
Jeff
3
Eh bien, nous devons souvent écrire des données dans des fichiers csv pour les lire par d'autres programmes. Le 00:00:00 redondant rend le traitement plus difficile en général, en particulier lorsque je travaille avec des données purement quotidiennes.

Réponses:

287

Depuis la version, 0.15.0cela peut maintenant être fait facilement en utilisant .dtpour accéder uniquement au composant date:

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

Ce qui précède renvoie un datetime.datedtype, si vous voulez en avoir un, datetime64vous pouvez simplement normalizele composant time à minuit afin qu'il définit toutes les valeurs à 00:00:00:

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

Cela conserve le dtype datetime64mais l'affichage n'affiche que la datevaleur.

EdChum
la source
33

Solution simple:

df['date_only'] = df['date_time_column'].dt.date
Gil Baggio
la source
Juste un avertissement, cela change le type en objet. Il vous faudrait donc taper ('datetime64') pour conserver la cohérence.
misantroop
25

Alors que j'ai surévalué la réponse d'EdChum, qui est la réponse la plus directe à la question posée par l'OP, elle ne résout pas vraiment le problème de performance (elle repose toujours sur des datetimeobjets python , et donc toute opération sur eux ne sera pas vectorisée - c'est-à-dire qu'elle sera lent).

Une alternative plus performante consiste à utiliser df['dates'].dt.floor('d'). À strictement parler, il ne "conserve que la partie date", car il ne fait que régler l'heure 00:00:00. Mais cela fonctionne comme souhaité par l'OP lorsque, par exemple:

  • impression sur écran
  • enregistrement en csv
  • en utilisant la colonne pour groupby

... et c'est beaucoup plus efficace, puisque l'opération est vectorisée.

EDIT: en fait, la réponse que les PO auraient préféré est probablement "les versions récentes de pandasn'écrivent pas l'heure en csv si c'est 00:00:00pour toutes les observations".

Pietro Battiston
la source
Malheureusement, to_jsonécrit toujours le plein 00:00:00.
IanS
@IanS voulez-vous dire lors de l'utilisation date_format='iso'?! Par défaut, il ne sort que quelques secondes depuis l'époque.
Pietro Battiston,
Oui, c'est ce que je voulais dire.
IanS
C'est plus rapide que dt.normalize()sur des séries de plus de quelques centaines d'éléments.
C8H10N4O2
16

Pandas DatetimeIndexet Seriesont une méthode appelée normalizequi fait exactement ce que vous voulez.

Vous pouvez en savoir plus à ce sujet dans cette réponse .

Il peut être utilisé comme ser.dt.normalize()

j08lue
la source
15

Pandas v0.13 +: utiliser to_csvavec le date_formatparamètre

Évitez, dans la mesure du possible, de convertir votre datetime64[ns]série en une objectsérie d' datetime.dateobjets dtype . Ce dernier, souvent construit en utilisant pd.Series.dt.date, est stocké sous forme de tableau de pointeurs et est inefficace par rapport à une série basée sur NumPy pur.

Puisque votre souci est le format lors de l'écriture en CSV , utilisez simplement le date_formatparamètre de to_csv. Par exemple:

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

Voir les strftimedirectives de Python pour les conventions de formatage.

jpp
la source
8

C'est un moyen simple d'extraire la date:

import pandas as pd

d='2015-01-08 22:44:09' 
date=pd.to_datetime(d).date()
print(date)
Mani Abi Anand
la source
L'OP utilise déjà la méthode .date () dans leur question, donc cette solution ne répond pas à leur question, mais j'ai trouvé utile de voir un exemple simple d'utilisation de la méthode date () comme référence.
Nic Scozzaro
5

Conversion en datetime64[D]:

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

Bien que réaffecter cela à un col DataFrame le ramènera à [ns].

Si vous vouliez du réel 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)])
Dale Jung
la source
3
Si vous utilisez un type ('M8 [D]'), il transforme les valeurs manquantes en date d'origine, 1970-1-1. Il vaut probablement mieux utiliser simplement pandas.to_datetime () de nos jours.
Stewbaca
1
Remarque à tous ceux qui incluent régulièrement le module datetime dt, ce snipet de réponse écrasera ce module! @ Dale-Jung, pourrait peut-être changer la ligne en quelque chose comme dt_index
yeliabsalohcin
Je trouve également un problème selon lequel la prochaine fois que j'essaierai d'ajouter une nouvelle ligne via la df.loc[date]méthode, l'index reviendra à un horodatage, ce qui signifie que les comparaisons ultérieures ne fonctionneront plus
yeliabsalohcin
3

Je donne juste une réponse plus à jour au cas où quelqu'un verrait ce vieux message.

L'ajout de "utc = False" lors de la conversion en datetime supprimera le composant de fuseau horaire et ne conservera que la date dans un type de données datetime64 [ns].

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

Vous pourrez l'enregistrer dans Excel sans obtenir l'erreur "ValueError: Excel ne prend pas en charge les heures avec des fuseaux horaires. Veuillez vous assurer que les heures ne sont pas au fuseau horaire avant d'écrire dans Excel."

entrez la description de l'image ici

Katekarin
la source
Cela pour une raison quelconque échoue après avoir appliqué une fonction d'agrégation à la colonne.
RaphX
0

Je voulais pouvoir changer le type d'un ensemble de colonnes dans un bloc de données, puis supprimer l'heure en gardant la journée. rond (), sol (), plafond () tous travaux

df[date_columns] = df[date_columns].apply(pd.to_datetime)
df[date_columns] = df[date_columns].apply(lambda t: t.dt.floor('d'))
Climbs_lika_Spyder
la source