Як змінити формат часу в пандах


109

Мій фрейм даних містить DOBстовпчик (приклад формат 1/1/2016), який за замовчуванням перетворюється на тип об'єкта pandas dtype:DOB object

Перетворення це формат дати з df['DOB'] = pd.to_datetime(df['DOB']), дата перетворюється в: 2016-01-26і його dtypeє: DOB datetime64[ns].

Тепер я хочу конвертувати цей формат дати 01/26/2016в будь-який інший загальний формат дати. Як це зробити?

Який би метод я не пробував, він завжди показує дату у 2016-01-26форматі.


Ви шукаєте рішення, яке працює лише під ноутбуком Юпітера? (у такому випадку використовуйте стилер для стовпців) або працює у звичайній консолі Python та iPython?
smci

Відповіді:


208

Ви можете використовувати, dt.strftimeякщо вам потрібно конвертувати datetimeв інші формати (але зауважте, що тоді dtypeстовпець буде 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
'strearch' перетворює стовпчик datetime в unicode для застосування операції на DOB1, ми знову повинні перетворити його в datetime. Чи немає іншого способу форматування, не втрачаючи тип даних?
М.Заман

@jezrael, чи є краще рішення, яке зберігає також тип даних і не повертає дати в стовпчик об'єкта? Проблема полягає в тому, що якщо спробувати перетворити його після рядка 'df [' DOB1 '] = df [' DOB ']. Dt.strWeather ('% m /% d /% Y ')', як це запропоновано в рішенні вище дати повертаються до початкового формату.
Ізгой

ха-ха, так як я можу це зробити, якщо я хочу використати тоді цей стовпець для .mergeстовпця дата-інтерфейсу іншого фрейму даних? Чи має сенс перетворювати інший стовпець дати в стовпець об'єкта, щоб це зробити .merge?
Ізгой

Так , мабуть , я згоден , але на «Не існує :(» ви сказали мені , що я не можу перетворити стовпець дати і часу після того, як змінює свій формат , не втрачаючи свій новий формат так.?
Ізгой

Гаразд, наскільки я розумію, це .mergeвсе ще можна зробити правильно, якщо обидва стовпці - це стовпці з датами, навіть якщо вони не мають точно однакового формату. Чи це правильно?
Ізгой

21

Зміна формату, але не зміна типу:

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

просто пам’ятайте, що df ["дата"] має бути datetime64 перед цим
adhg

4
Немає! Припустимо, початкова вартість якогось елемента у dateстовпці - « 26 листопада 2019 року». strftime()означає "рядок від часу" , таким чином df["date"].dt.strftime('%Y-%m')буде рядком "2019-11" для цього елемента. Потім pd.to_datetime()перетворимо цей рядок назад у datetime64формат, але тепер як « 1 листопада 2019 року»! Таким чином, результат буде: Не зміна формату, а зміна самого значення дати!
MarianD

2
@MarianD: всі ваші коментарі до окремих відповідей корисні, але ви можете, будь ласка, узагальнити їх у одному зі списку "Підводні камені / Не робіть цього" внизу вашої відповіді? Також вам потрібно чітко вказати, у чому полягає проблема з кожною з них: якщо будь-яка дата введення не в очікуваному форматі, вони або ризикують викинути винятки, або змішать дату. Просто напишіть "Ні!" скрізь цього не передає.
smci

8

Наведений нижче код працював для мене замість попереднього - спробуйте!

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

2
Немає! Ваш format='%m/%d/%Y'параметр призначений для розбору рядка, тобто вам слід надати рядок у такому форматі (наприклад, "5/13/2019"). Більше нічого, без зміни формату. Він все ще відображатиметься як 2019-05-13- або створить виняток, якщо він df['DOB'].astype(str)містить елементи, які не в такому форматі, наприклад у форматі "2019-05-13".
MarianD

4

Порівняно з першою відповіддю, я порекомендую спочатку використовувати dt.strearch (), а потім pd.to_datetime (). Таким чином, це все одно призведе до типу даних datetime.

Наприклад,

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
Принаймні, в моєму випадку це не працює. Зокрема, стовпець перетворюється на тип даних дати, але також значення перетворюються у вихідний формат!
Ізгой

Немає! Помилка синтаксису (відсутня дужка), у моїй версії Pandas (0.25.1) ще одна синтаксична помилка (dt.strearch () - може використовувати лише .dt-аксесуар із значеннями datetime) - ви покладаєтесь на притаманний тип даних, але в різних версіях Пандам властиві типи даних можуть бути різними), і дивна логіка - навіщо перетворювати дату в рядок, а потім повертатися в дату ? Дивіться мій коментар до відповіді Ріші Джин.
MarianD

2

Існує різниця між

  • зміст з dataframe осередки (двійкове значення) і
  • його презентація (показ її) для нас, людей.

Отже, питання: Як досягти відповідної презентації моїх даних без зміни самих даних / типів даних?

Ось відповідь:

  • Якщо ви використовуєте ноутбук Юпітера для відображення свого фрейму даних, або
  • якщо ви хочете отримати презентацію у вигляді HTML-файлу (навіть із багатьма підготовленими зайвими idта classатрибутами для подальшого стилю CSS - ви можете або не можете їх використовувати),

використовувати стайлінг . Стилі не змінюють типи даних / типи даних стовпців вашого фрейму даних.

Тепер я показую, як досягти цього в зошиті Юпітера - для презентації у вигляді HTML-файлу дивіться примітку наприкінці запитання.

Я припускаю, що ваш стовпець DOB вже має типdatetime64 (ви показали, що знаєте, як його досягти). Я підготував простий кадр даних (лише з одним стовпцем), щоб показати вам основні стилі:

  • Не стилізовано:

       df
          DOB
0  2019-07-03
1  2019-08-03
2  2019-09-03
3  2019-10-03
  • Стилізуючи його як 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
  • Стилізуючи його як 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

Будь обережний!
Об'єкт, що повертається, НЕ є фреймом даних - це об’єкт класу Styler, тому не призначайте його назад df:

Не робіть цього:

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

(Кожен фрейм даних має свій об'єкт Styler, доступний за його .styleвластивістю. Ми змінили цей df.styleоб'єкт, а не сам кадр даних.)


Питання та відповіді:

  • З: Чому ваш об’єкт Styler (або вираз, що повертає його), що використовується як остання команда в комірці ноутбука Юпітера, відображає вашу ( стильову ) таблицю , а не сам об’єкт Styler?

  • Відповідь: Оскільки кожен об'єкт Styler має метод зворотного виклику, ._repr_html_()який повертає HTML-код для візуалізації вашої кадри даних (як хороша таблиця HTML).

    IDE Jupyter Notebook викликає цей метод автоматично, щоб відобразити об'єкти, які в ньому є.


Примітка:

Вам не потрібен ноутбук Юпітера для стилізації (тобто для гарного виведення фрейму даних без зміни його типів даних / даних ).

Об'єкт Styler також має метод render(), якщо ви хочете отримати рядок з кодом HTML (наприклад, для публікації свого відформатованого фрейму даних в Інтернеті або просто представити свою таблицю у форматі HTML):

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

Варто зазначити, що такий код стилера призначений для запуску, і він набуває чинності лише в ноутбуці Юпітера і має абсолютно нульовий ефект при запуску в консолі чи iPython . В ОП не було вказано "під Юпітером", тому це може бути, а може і не бути життєздатним рішенням залежно від їх налаштування. Багато коду наукових даних отримує копіювання та вставлення, а припущення, що стосуються Юпітера, не вказуються явно, то люди задаються питанням, чому код стилера "не працює", коли він працює у своєму (консольному) середовищі.
smci

@smci, чи не вказано прямо в другому абзаці моєї відповіді? У формі умовного if, твердження, так відомо кожному програмісту? - Незважаючи на те, що дякуємо за ваш коментар, це може бути корисним для деяких людей.
MarianD

ні, це дуже незрозуміло, також поховано. Оригінальне запитання нічого не передбачало щодо Юпітера, а ОП та деякі користувачі можуть навіть не мати Юпітера. У вашій відповіді потрібно жирним шрифтом сказати перший рядок: "Наступний підхід (стилізація) працює лише в блокноті Юпітера, і не матиме жодного ефекту, коли ви працюєте за межами ноутбука Юпітера" . (У блогах та на сайтах із науковими даними я щодня бачу, як люди публікують код Юпітера в середовищі, що не є Юпітером, і цікаво, чому це не працює).
smci

Класно. Я також пропоную вам додати всі (безліч) підводних каменів, які ви виявили на інших підходах "перетворити на рядок-з-строком-потім-назад-знову-з-pd.to_datetime". Принаймні, потрібно згадати про підвищення та вилучення винятків. Крім того, pd.to_datetime()є аргументи, errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactщоб контролювати, наскільки він точний і задоволений винятками, а також чи примушують недійсні виходи до NaTчого. Що ускладнює в наборах даних "реального світу" змішані / відсутні / неповні формати, час, часові пояси тощо; винятки - це не обов'язково погані речі.
smci

... інакше я можу це написати як скупчення підводних каменів у не-Юпітерських підходах.
smci

1

Нижче код змінюється на тип 'datetime', а також формати в заданому рядку формату. Добре працює!

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

2
змінити це на це:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
Джон Доу

Немає! - Навіщо перетворювати дату в рядок, а потім повертати в дату ? Дивіться мої коментарі до інших відповідей.
MarianD

1

Ви можете спробувати, це перетворить формат дати в DD-MM-YYYY:

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

Немає! dayfirst=Trueє лише специфікацією порядку розбору дати, наприклад, що амбівалентний рядок дати як "2-1-2019" буде проаналізований як 2 січня 2019 року, а не як 1 лютого 2019 року. Більше, ніяких змін для форматування виводу .
MarianD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.