Comment changer le format datetime dans les pandas

109

Mon dataframe a une DOBcolonne (exemple de format 1/1/2016) qui par défaut est convertie en pandas dtype 'object':DOB object

La conversion de ce format de date avec df['DOB'] = pd.to_datetime(df['DOB']), la date est convertie en: 2016-01-26et son dtypeest: DOB datetime64[ns].

Maintenant, je veux convertir ce format de date vers 01/26/2016ou dans tout autre format de date général. Comment fait-on ça?

Quelle que soit la méthode que j'essaie, elle affiche toujours la date au 2016-01-26format.

yo moi
la source
Vous recherchez une solution qui ne fonctionne que sous le notebook Jupyter? (dans ce cas, utilisez un 'styler' par colonne) ou fonctionne dans la console Python ordinaire et iPython?
smci

Réponses:

209

Vous pouvez utiliser dt.strftimesi vous avez besoin de convertir datetimevers d'autres formats (mais notez que la dtypecolonne sera 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
la source
32
'strftime' convertit la colonne datetime en unicode pour appliquer l'opération sur DOB1, nous devons à nouveau la convertir en datetime. N'y a-t-il pas d'autre moyen de formater sans perdre le data_type?
M.Zaman
@jezrael, y a-t-il une meilleure solution qui conserve également le type de données et ne renvoie pas les dates dans une colonne d'objet? Le problème est que si vous essayez de le convertir après la ligne 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')' comme il est suggéré à la solution ci-dessus, les dates reviennent à leur format d'origine.
Paria le
haha, alors comment puis-je faire cela si je veux utiliser cette colonne pour une .mergecolonne datetime d'une autre dataframe? Est-il judicieux de convertir l'autre colonne datetime en colonne d'objet pour faire le .merge?
Paria le
Oui apparemment j'accepte mais par "Not exist :(" tu m'as dit que je ne peux pas convertir la colonne en datetime après avoir changé son format sans perdre son nouveau format. Alors?
Outcast
Ok, pour autant que je sache, cela .mergepeut toujours être fait correctement si les deux colonnes sont des colonnes datetimes même si elles n'ont pas exactement le même format. Est-ce correct?
Paria le
21

Changer le format mais pas changer le type:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Yanni Cao
la source
rappelez-vous simplement que df ["date"] doit être datetime64 avant de faire cela
adhg
4
Non! Supposons que la valeur d'origine d'un élément de la datecolonne soit « 26 novembre 2019». strftime()signifie "chaîne de temps" , ainsi df["date"].dt.strftime('%Y-%m')sera une chaîne "2019-11" pour cet élément. Ensuite, pd.to_datetime()convertira cette chaîne de retour au datetime64format, mais maintenant « Novembre 1 , 2019 »! Le résultat sera donc: Aucun changement de format, mais le changement de la valeur de la date elle-même!
MarianD
2
@MarianD: tous vos commentaires sur les réponses individuelles sont utiles, mais pouvez-vous les résumer en un seul résumé de "Pièges / Ne pas faire ces" au bas de votre réponse? Vous devez également indiquer clairement quel est le problème avec chacun d'eux: si l'une des dates d'entrée n'est pas dans le format attendu, elles risquent soit de générer des exceptions, soit de modifier la date. Ecrire simplement "Non!" partout ne transmet pas cela.
smci
8

Le code ci-dessous a fonctionné pour moi au lieu du précédent - essayez-le!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')
rishi jain
la source
2
Non! Votre format='%m/%d/%Y'paramètre est pour analyser une chaîne, c'est-à-dire que vous êtes censé fournir la chaîne dans un tel format (par exemple "5/13/2019"). Rien de plus, pas de changement de format. Il sera toujours affiché comme 2019-05-13- ou il déclenchera une exception, s'il df['DOB'].astype(str)contient des éléments qui ne sont pas dans un tel format, par exemple dans un format "2019-05-13".
MarianD
4

Par rapport à la première réponse, je recommanderai d'utiliser d'abord dt.strftime (), puis pd.to_datetime (). De cette manière, il en résultera toujours le type de données datetime.

Par exemple,

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
la source
2
Cela ne fonctionne pas du moins dans mon cas. Plus précisément, la colonne est convertie en type de données datetime, mais les valeurs sont également converties au format d'origine!
Paria le
Non! Erreur de syntaxe (accolade manquante), dans ma version de Pandas (0.25.1) une autre erreur de syntaxe (dt.strftime () - ne peut utiliser l'accesseur .dt qu'avec des valeurs datetimelike) - vous vous fiez au type de données inhérent, mais dans différentes versions de Pandas, les types de données inhérents peuvent être différents), et une logique étrange - pourquoi convertir datetime en chaîne, puis revenir en datetime ? Voir mon commentaire sur la réponse de rishi jain.
MarianD
2

Il y a une différence entre

  • le contenu d'une cellule de dataframe (une valeur binaire) et
  • sa présentation (l'afficher) pour nous, humains.

La question est donc: comment parvenir à la présentation appropriée de mes données sans changer les données / types de données eux-mêmes?

Voici la réponse:

  • Si vous utilisez le notebook Jupyter pour afficher votre dataframe, ou
  • si vous voulez atteindre une présentation sous la forme d'un fichier HTML (même avec de nombreux superflus préparés idet des classattributs pour un style CSS ultérieur - vous pouvez ou vous ne pouvez pas les utiliser),

utilisez le style .Le style ne change pas les données / types de données des colonnes de votre dataframe.

Maintenant, je vous montre comment y accéder dans le notebook Jupyter - pour une présentation sous forme de fichier HTML, voir la note à la fin de la question.

Je suppose que votre colonne a DOB déjà le typedatetime64 (vous avez montré que vous savez comment y accéder). J'ai préparé un dataframe simple (avec une seule colonne) pour vous montrer un style de base:

  • Pas de style:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Le styliser comme 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
  • Le styliser comme 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

Faites attention!
L'objet renvoyé n'est PAS un dataframe - c'est un objet de la classe Styler, alors ne le réattribuez pas à df:

Ne faites pas ça:

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

(Chaque dataframe a son objet Styler accessible par sa .stylepropriété, et nous avons changé cet df.styleobjet, pas le dataframe lui-même.)


Questions et réponses:

  • Q: Pourquoi votre objet Styler (ou une expression le renvoyant) utilisé comme dernière commande dans une cellule de bloc-notes Jupyter affiche votre tableau (stylisé) et non l'objet Styler lui-même?

  • R: Parce que chaque objet Styler a une méthode de rappel ._repr_html_()qui renvoie un code HTML pour le rendu de votre dataframe (sous la forme d'un joli tableau HTML).

    Jupyter Notebook IDE appelle cette méthode automatiquement pour rendre les objets qui en ont.


Remarque:

Vous n'avez pas besoin du notebook Jupyter pour le style (c'est-à-dire pour une sortie agréable d'une trame de données sans changer ses données / types de données ).

Un objet Styler a également une méthode render(), si vous souhaitez obtenir une chaîne avec le code HTML (par exemple pour publier votre dataframe formaté sur le Web, ou simplement présenter votre tableau au format HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
MarianD
la source
Il convient de souligner que le code de style comme celui-ci est destiné à être exécuté sous, et ne prend effet que sous le notebook Jupyter, et n'a absolument aucun effet lorsqu'il est exécuté dans la console ou iPython . L'OP n'a pas spécifié "sous Jupyter", donc cela peut ou non être une solution viable en fonction de leur configuration. Beaucoup de code de science des données est copié-collé, et les hypothèses spécifiques à Jupyter ne sont pas explicitement spécifiées, alors les gens se demandent pourquoi le code du styler «ne fonctionne pas» lorsqu'il est exécuté dans leur environnement (console).
smci
@smci, n'est-il pas explicitement mentionné dans le deuxième paragraphe de ma réponse? Sous la forme d'une ifinstruction conditionnelle si connue de tous les programmeurs? - Malgré cela merci pour votre commentaire, cela peut être utile pour certaines personnes.
MarianD
non c'est très peu clair, également enterré. La question originale ne supposait rien à propos de Jupyter, et l'OP et certains utilisateurs peuvent même ne pas avoir Jupyter à leur disposition. Votre réponse devrait indiquer en gras sa première ligne "L'approche suivante (style) ne fonctionne que sous le notebook Jupyter et n'aura aucun effet si elle est exécutée en dehors du notebook Jupyter" . (Dans les blogs et sites de science des données, je vois quotidiennement des gens qui publient du code Jupyter dans des environnements non Jupyter et se demandent pourquoi cela ne fonctionne pas).
smci
Cool. Je vous suggère également d'ajouter tous les (nombreux) pièges que vous avez identifiés sur les autres approches "convert-to-string-with-strftime-then-back-again-with-pd.to_datetime". Au moins, il faut mentionner la levée et la capture d'exceptions. En outre, pd.to_datetime()a les arguments errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactpour contrôler la précision et la satisfaction des exceptions, et si les sorties invalides sont forcées NaTou quoi. Ce qui le rend plus compliqué dans les ensembles de données «du monde réel», ce sont les formats mixtes / manquants / incomplets, les heures, les fuseaux horaires, etc. les exceptions ne sont pas nécessairement de mauvaises choses.
smci
... ou bien je peux écrire cela comme un cumul de pièges dans les approches non-Jupyter.
smci
1

Le code ci-dessous passe au type 'datetime' et se met également en forme dans la chaîne de format donnée. Fonctionne bien!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))
San
la source
2
changez-le en ceci:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe
Non! - Pourquoi convertir datetime en string puis revenir en datetime ? Voir mes commentaires sur les autres réponses.
MarianD
1

Vous pouvez essayer ceci, cela convertira le format de date en JJ-MM-AAAA:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
la source
Non! dayfirst=Trueest uniquement la spécification d'un ordre d'analyse de date, par exemple cette chaîne de date ambivalente en tant que "2-1-2019" sera analysée en tant que 2 janvier 2019, et non en tant que 1er février 2019. Rien de plus, pas de changement pour le formatage de sortie .
MarianD