Как изменить формат даты и времени в пандах

113

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

Преобразование это формат даты с df['DOB'] = pd.to_datetime(df['DOB']), дата преобразуется в: 2016-01-26и его dtypeявляется: DOB datetime64[ns].

Теперь я хочу преобразовать этот формат даты 01/26/2016в любой другой общий формат даты или в любой другой. Как мне это сделать?

Какой бы метод я ни пробовал, он всегда показывает дату в 2016-01-26формате.

йом
источник
Вы ищете решение, которое работает только с ноутбуком Jupyter? (в каком случае использовать стилизатор для каждого столбца) или работает в простой консоли Python и iPython?
smci

Ответы:

216

Вы можете использовать, 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
Jezrael
источник
32
'strftime' преобразует столбец datetime в unicode для применения операции к DOB1, мы снова должны преобразовать его в datetime. Нет ли другого способа форматирования без потери data_type?
M.Zaman
1
@jezrael, есть ли лучшее решение, которое сохраняет также тип данных и не возвращает даты в столбец объекта? Проблема в том, что если попытаться преобразовать его после строки 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')', как это предлагается в решении выше, даты возвращаются к исходному формату.
Outcast
ха-ха, так как я могу это сделать, если я хочу использовать этот столбец для .mergeстолбца datetime другого фрейма данных? Имеет ли смысл преобразовывать другой столбец datetime в столбец объекта, чтобы сделать это .merge?
Outcast
Да, видимо, я согласен, но с помощью «Не существует :(» вы сказали мне, что я не могу преобразовать столбец в datetime после изменения его формата без потери нового формата. Итак?
Outcast
Хорошо, насколько я понимаю, это .mergeможно сделать правильно, если оба столбца являются столбцами даты и времени, даже если они не имеют точно такого же формата. Это правильно?
Outcast
21

Изменение формата, но без изменения типа:

df['date'] = pd.to_datetime(df["date"].dt.strftime('%Y-%m'))
Янни Цао
источник
просто помните, что перед этим df ["date"] должно быть 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
5

По сравнению с первым ответом я рекомендую сначала использовать dt.strftime (), а затем 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)
user3512680
источник
2
По крайней мере, в моем случае это не работает. В частности, столбец преобразуется в тип данных datetime, но также значения преобразуются в исходный формат!
Изгой
Нет! Синтаксическая ошибка (отсутствует фигурная скобка), в моей версии Pandas (0.25.1) другая синтаксическая ошибка (dt.strftime () - может использовать только аксессор .dt со значениями типа datetime) - вы полагаетесь на собственный тип данных, но в разных версиях Pandas присущие типы данных могут быть разными) и странная логика - зачем конвертировать datetime в строку, а затем обратно в datetime ? См. Мой комментарий к ответу риши джайна.
MarianD
2

Вы можете попробовать это, он преобразует формат даты в ДД-ММ-ГГГГ:

df['DOB'] = pd.to_datetime(df['DOB'], dayfirst = True)
Ashu007
источник
Нет! dayfirst=Trueэто всего лишь спецификация порядка синтаксического анализа даты, например, эта амбивалентная строка даты как «2-1-2019» будет анализироваться как 2 января 2019 года, а не как 1 февраля 2019 года. Ничего более, никаких изменений для форматирования вывода .
MarianD
2

Есть разница между

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

Возникает вопрос: как достичь надлежащего представления моих данных без изменения самих данных / типов данных?

Вот ответ:

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

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

Теперь я покажу вам, как добраться до него в записной книжке Jupyter - для презентации в виде файла 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 (или возвращающее его выражение), используемый в качестве последней команды в ячейке записной книжки Jupyter, отображает вашу (стилизованную) таблицу , а не сам объект Styler?

  • A: Потому что каждый объект Styler имеет метод обратного вызова, ._repr_html_()который возвращает HTML-код для рендеринга вашего фрейма данных (в виде красивой HTML-таблицы).

    Jupyter Notebook IDE автоматически вызывает этот метод для визуализации объектов, в которых он есть.


Примечание:

Записная книжка Jupyter не нужна для стилизации (т.е. для хорошего вывода фрейма данных без изменения его данных / типов данных ).

У объекта Styler также есть метод render(), если вы хотите получить строку с кодом HTML (например, для публикации вашего отформатированного фрейма данных в Интернете или просто представить вашу таблицу в формате HTML):

df_styler = df.style.format({"DOB": lambda t: t.strftime("%m/%d/%Y")})
HTML_string = df_styler.render()
МарианД
источник
Стоит отметить, что подобный код стилизатора предназначен для запуска под управлением и действует только под ноутбуком Jupyter и не имеет абсолютно никакого эффекта при запуске в консоли или iPython . OP не указал «под Jupyter», поэтому это может быть или не может быть жизнеспособным решением в зависимости от их настройки. Большая часть кода науки о данных копируется и вставляется, а специфические для Jupyter предположения не указываются явно, тогда люди задаются вопросом, почему код стилизатора «не работает» при запуске в их (консольной) среде.
smci
@smci, разве это явно не упоминается во втором абзаце моего ответа? В виде условного ifоператора, известного каждому программисту? - Несмотря на это, спасибо за комментарий, некоторым людям он может быть полезен.
MarianD
нет это очень непонятно, тоже похоронен. Исходный вопрос ничего не предполагал о Jupyter, а OP и некоторые пользователи могут даже не иметь Jupyter, доступного для них. В вашем ответе первая строка должна быть выделена жирным шрифтом: «Следующий подход (стиль) работает только в блокноте Jupyter и не будет иметь никакого эффекта при запуске вне блокнота Jupyter» . (В блогах и на сайтах по науке о данных я ежедневно вижу людей, которые публикуют код Jupyter в среде, отличной от Jupyter, и задаются вопросом, почему он не работает).
smci
Прохладно. Я также предлагаю вам добавить все (многие) подводные камни, которые вы определили при использовании других подходов «преобразовать в строку с помощью strftime-затем-обратно-снова-с-pd.to_datetime». По крайней мере, нужно упомянуть о возбуждении и отлове исключений. Кроме того, у pd.to_datetime()него есть аргументы errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactдля управления тем, насколько он точен и благоприятен для исключений, и будут ли принудительно выполняться недопустимые выходные данные NaTили что. Что делает его более сложным в «реальных» наборах данных, так это смешанные / отсутствующие / неполные форматы, время, часовые пояса и т. Д .; исключения не обязательно плохие.
smci
... или я могу написать это как совокупность подводных камней в подходах, отличных от Jupyter.
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')
Джон Доу
Нет! - Зачем преобразовывать datetime в строку, а затем обратно в datetime ? Смотрите мои комментарии к другим ответам.
MarianD