Jak zmienić format daty i godziny w pandach

109

Moja ramka danych ma DOBkolumnę (przykładowy format 1/1/2016), która jest domyślnie konwertowana na pandas dtype 'object':DOB object

Konwersja to format daty df['DOB'] = pd.to_datetime(df['DOB']), data zostanie przekonwertowany do: 2016-01-26a jej dtypebrzmi: DOB datetime64[ns].

Teraz chcę przekonwertować ten format daty na 01/26/2016lub w inne ogólne formaty daty. Jak mam to zrobić?

Niezależnie od metody, którą wypróbuję, zawsze pokazuje datę w 2016-01-26formacie.

yome
źródło
Szukasz rozwiązania, które działa tylko pod notebookiem Jupyter? (w takim przypadku użyj „stylera” dla każdej kolumny) lub działa w zwykłej konsoli Pythona i iPythonie?
smci

Odpowiedzi:

209

Możesz użyć, dt.strftimejeśli chcesz przekonwertować datetimena inne formaty (ale pamiętaj, że wtedy dtypekolumna będzie 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
źródło
32
„strftime” konwertuje kolumnę datetime na Unicode w celu zastosowania operacji na DOB1, musimy ponownie przekonwertować ją na datetime. Czy nie ma innego sposobu formatowania bez utraty parametru data_type?
M.Zaman
@jezrael, czy jest jakieś lepsze rozwiązanie, które zachowuje również typ danych i nie zwraca dat do kolumny obiektu? Problem polega na tym, że jeśli spróbujesz przekonwertować go po wierszu 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')', jak to sugeruje rozwiązanie powyżej daty wracają do swojego pierwotnego formatu.
Outcast
haha, więc jak mogę to zrobić, jeśli chcę użyć tej kolumny dla .mergekolumny datetime innej ramki danych? Czy ma sens konwertowanie drugiej kolumny daty i godziny na kolumnę obiektu, aby wykonać .merge?
Outcast
Tak, najwyraźniej zgadzam się, ale przez „Nie istnieje :(” powiedziałeś mi, że nie mogę przekonwertować kolumny na datę i godzinę po zmianie jej formatu bez utraty nowego formatu. Więc?
Outcast
Ok, o ile rozumiem, .mergenadal można to zrobić poprawnie, jeśli obie kolumny są kolumnami czasu danych, nawet jeśli nie mają dokładnie tego samego formatu. Czy to jest poprawne?
Outcast
21

Zmiana formatu, ale bez zmiany typu:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Yanni Cao
źródło
pamiętaj tylko, że df ["date"] powinno być datetime64, zanim to zrobisz
adhg
4
Nie! Załóżmy, że pierwotna wartość jakiegoś elementu w datekolumnie to „ 26 listopada 2019 r.”. strftime()oznacza „ciąg od czasu” , więc df["date"].dt.strftime('%Y-%m')będzie ciągiem "2019-11" dla tego elementu. Następnie pd.to_datetime()przekonwertuje ten ciąg z powrotem do datetime64formatu, ale teraz jako „ 1 listopada 2019”! Wynik będzie więc: Bez zmiany formatu, ale zmiana samej wartości daty!
MarianD
2
@MarianD: wszystkie twoje komentarze do poszczególnych odpowiedzi są przydatne, ale czy możesz podsumować je w jednym zbiorczym zestawieniu „Pułapki / Nie rób tych” u dołu odpowiedzi? Musisz również jasno określić, na czym polega problem z każdym z nich: jeśli którakolwiek z dat wejściowych nie jest w oczekiwanym formacie, może to spowodować rzucenie wyjątków lub zmianę daty. Po prostu pisząc „Nie!” wszędzie tego nie widać.
smci
8

Poniższy kod zadziałał dla mnie zamiast poprzedniego - wypróbuj!

df['DOB']=pd.to_datetime(df['DOB'].astype(str), format='%m/%d/%Y')
rishi jain
źródło
2
Nie! Twój format='%m/%d/%Y'parametr służy do parsowania napisu, tzn. Powinieneś dostarczyć napis w takim formacie (np "5/13/2019".). Nic więcej, bez zmiany formatu. Nadal będzie wyświetlany jako 2019-05-13- lub zgłosi wyjątek, jeśli df['DOB'].astype(str)zawiera element (y) nie w takim formacie, np. W formacie "2019-05-13".
MarianD
4

W porównaniu z pierwszą odpowiedzią zalecam najpierw użycie dt.strftime (), a następnie pd.to_datetime (). W ten sposób nadal będzie skutkował typem danych datetime.

Na przykład,

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
źródło
2
To nie działa przynajmniej w moim przypadku. W szczególności kolumna jest konwertowana na typ danych datetime, ale także wartości są konwertowane do formatu oryginalnego!
Outcast
Nie! Błąd składniowy (brak nawiasu klamrowego), w mojej wersji Pandas (0.25.1) inny błąd składniowy (dt.strftime () - można używać tylko akcesora .dt z wartościami podobnymi do danych) - polegasz na typie danych, ale w różnych wersjach Pandy, nieodłączne typy danych mogą być różne) i dziwna logika - po co konwertować datę i godzinę na łańcuch, a potem z powrotem na datę i godzinę ? Zobacz mój komentarz do odpowiedzi rishi jain.
MarianD
2

Jest różnica między

  • zawartość komórki dataframe (wartość binarna) i
  • jego prezentacja (wyświetlanie) dla nas, ludzi.

Pytanie brzmi: jak dojść do odpowiedniej prezentacji moich danych bez zmiany samych danych / typów danych?

Oto odpowiedź:

  • Jeśli używasz notatnika Jupyter do wyświetlania ramki danych lub
  • jeśli chcesz dotrzeć do prezentacji w postaci pliku HTML (nawet z wieloma przygotowanymi zbędnymi idi classatrybutami do dalszego stylowania CSS - możesz ich użyć lub nie),

użyj stylizacji .Styl nie zmienia danych / typów danych kolumn ramki danych.

Teraz pokażę Ci, jak dotrzeć do tego w notatniku Jupyter - aby zapoznać się z prezentacją w postaci pliku HTML, zobacz notatkę pod koniec pytania.

Przypuszczam, że twoja kolumna DOB ma już typdatetime64 (pokazałeś, że wiesz, jak do niego dotrzeć). Przygotowałem prostą ramkę danych (z tylko jedną kolumną), aby pokazać podstawowe style:

  • Nie stylizowany:

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

Bądź ostrożny!
Zwracający obiekt NIE jest ramką danych - jest to obiekt klasy Styler, więc nie przypisuj go z powrotem do df:

Nie rób tego:

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

(Każda ramka danych ma swój obiekt Styler dostępny przez swoją .stylewłaściwość i zmieniliśmy ten df.styleobiekt, a nie samą ramkę danych).


Pytania i odpowiedzi:

  • P: Dlaczego twój obiekt Styler (lub wyrażenie zwracające go) użyty jako ostatnie polecenie w komórce notatnika Jupyter wyświetla twoją (ze stylem) tabelę , a nie sam obiekt Styler?

  • Odp .: Ponieważ każdy obiekt Styler ma metodę wywołania zwrotnego, ._repr_html_()która zwraca kod HTML do renderowania ramki danych (jako ładnej tabeli HTML).

    Jupyter Notebook IDE wywołuje tę metodę automatycznie, aby renderować obiekty, które ją zawierają.


Uwaga:

Nie potrzebujesz notatnika Jupyter do stylizacji (tj. Do ładnego drukowania ramki danych bez zmiany jej typów danych / danych ).

Obiekt Styler ma również metodę render(), jeśli chcesz uzyskać ciąg znaków z kodem HTML (np. Do opublikowania sformatowanej ramki danych w Internecie lub po prostu zaprezentuj swoją tabelę w formacie HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
MarianD
źródło
Warto zauważyć, że taki kod stylera jest przeznaczony do uruchamiania pod kontrolą i działa tylko pod notebookiem Jupyter i ma absolutnie zerowy wpływ, gdy jest uruchamiany na konsoli lub iPythonie . W OP nie określono „pod Jupyter”, więc może to być lub nie być realnym rozwiązaniem w zależności od ich konfiguracji. Wiele kodu do nauki o danych jest kopiowanych i wklejanych, a założenia specyficzne dla Jupyter nie są wyraźnie określone, ludzie zastanawiają się, dlaczego kod stylera „nie działa”, gdy jest uruchamiany w ich środowisku (konsoli).
smci
@smci, czy nie jest wyraźnie wymienione w drugim akapicie mojej odpowiedzi? W postaci ifinstrukcji warunkowej tak znanej każdemu programiście? - Mimo to dziękuję za komentarz, dla niektórych może być pomocny.
MarianD
nie, to bardzo niejasne, również pochowany. Pierwotne pytanie nie miało nic wspólnego z Jupyter, a OP i niektórzy użytkownicy mogą nawet nie mieć Jupytera. W Twojej odpowiedzi należałoby napisać pogrubioną czcionką pierwszą linię: „Poniższe podejście (stylizacja) działa tylko w przypadku notatnika Jupyter i nie będzie miało żadnego wpływu, gdy zostanie uruchomione poza notatnikiem Jupyter” . (Na blogach i witrynach związanych z nauką o danych, które codziennie widzę, ludzie publikują kod Jupyter w środowiskach innych niż Jupyter i zastanawiają się, dlaczego to nie działa).
smci
Chłodny. Sugeruję również, abyś dodał wszystkie (wiele) pułapek, które zidentyfikowałeś w innych podejściach „konwertuj-na-ciąg-z-strftime-to-ponownie-z-pd.to_datetime”. Przynajmniej trzeba wspomnieć o podnoszeniu i łapaniu wyjątków. Ponadto, pd.to_datetime()ma argumenty errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exact, aby kontrolować sposób precyzyjny i wyjątków zadowolony to jest i czy nieprawidłowe wyjścia uzyskać zmuszony do NaTlub co. To, co sprawia, że ​​jest to bardziej skomplikowane w „rzeczywistych” zbiorach danych, to mieszane / brakujące / niekompletne formaty, godziny, strefy czasowe itp .; wyjątki niekoniecznie są złymi rzeczami.
smci
... albo mogę to napisać jako zbiór pułapek w podejściach innych niż Jupyter.
smci
1

Poniższy kod zmienia się na typ „datetime”, a także formatuje w podanym ciągu formatu. Działa dobrze!

df['DOB']=pd.to_datetime(df['DOB'].dt.strftime('%m/%d/%Y'))
San
źródło
2
zmień to na to:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
John Doe
Nie! - Po co konwertować datę i godzinę na ciąg, a następnie z powrotem na datę i godzinę ? Zobacz moje komentarze do innych odpowiedzi.
MarianD
1

Możesz spróbować tego, aby przekonwertować format daty na DD-MM-RRRR:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
źródło
Nie! dayfirst=Trueto tylko specyfikacja kolejności przetwarzania dat, np. ten niejednoznaczny ciąg daty jako „2-1-2019” zostanie przeanalizowany jako 2 stycznia 2019 r., a nie jako 1 lutego 2019 r. Nic więcej, bez zmian w formatowaniu danych wyjściowych .
MarianD