Como alterar o formato de data e hora no pandas


109

Meu dataframe tem uma DOBcoluna (formato de exemplo 1/1/2016) que, por padrão, é convertida para 'objeto' do tipo pandas dtype:DOB object

Convertendo isso para formato de data com df['DOB'] = pd.to_datetime(df['DOB']), a data é convertido em: 2016-01-26e sua dtypeé: DOB datetime64[ns].

Agora, quero converter esse formato de data para 01/26/2016ou em qualquer outro formato de data geral. Como eu faço isso?

Qualquer que seja o método que tente, sempre mostra a data no 2016-01-26formato.


Você está procurando uma solução que funcione apenas no notebook Jupyter? (nesse caso, use um 'estilizador' por coluna) ou funciona no console Python simples e no iPython?
— smci

Respostas:


208

Você pode usar dt.strftimese precisar converterdatetime para outros formatos (mas observe que então dtypeda coluna será 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
'strftime' converte a coluna datetime em unicode para aplicar a operação em DOB1, novamente temos que convertê-la em datetime. Não existe outra forma de formatação sem perder o data_type?
— M.Zaman

@jezrael, existe alguma solução melhor que retém também o tipo de dados e não retorna as datas para uma coluna de objeto? O problema é que se tentar convertê-lo após a linha 'df [' DOB1 '] = df [' DOB ']. Dt.strftime ('% m /% d /% Y ')', conforme sugerido na solução acima, as datas voltam ao formato original.
— Pária de

haha, então como posso fazer isso se eu quiser usar essa coluna para uma .mergecoluna datetime de outro dataframe? Faz algum sentido converter a outra coluna datetime em uma coluna de objeto para fazer o .merge?
— Pária de

Sim, aparentemente eu concordo, mas por "Não existe :(" você me disse que não consigo converter a coluna para datetime após alterar seu formato sem perder seu novo formato. Então?
— Proibido

Ok, pelo que eu entendi, .mergeisso ainda pode ser feito corretamente se ambas as colunas forem colunas de data e hora, mesmo que não tenham exatamente o mesmo formato. Isto está certo?
— Pária em

21

Mudar o formato, mas não mudar o tipo:

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

lembre-se de que df ["data"] deve ser datetime64 antes de você fazer isso
— adhg

4
Não! Suponha que o valor original de algum item da datecoluna seja “ 26 de novembro de 2019”. strftime()significa "string do tempo" , então df["date"].dt.strftime('%Y-%m')será uma string "2019-11" para esse item. Então, pd.to_datetime()irá converter esta string de volta para o datetime64formato, mas agora como “ 1 de novembro de 2019”! Portanto, o resultado será: Nenhuma mudança de formato, mas a mudança do próprio valor de data!
— MarianD

2
@MarianD: todos os seus comentários sobre as respostas individuais são úteis, mas você pode resumi-los em uma lista de "Armadilhas / Não faça isso" no final da sua resposta? Além disso, você precisa declarar claramente qual é o problema com cada um deles: se qualquer uma das datas de entrada não estiver no formato esperado, elas correrão o risco de gerar exceções ou destruirão a data. Simplesmente escrevendo "Não!" em todos os lugares não transmite isso.
— smci

8

O código abaixo funcionou para mim em vez do anterior - experimente!

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

2
Não! Seu format='%m/%d/%Y'parâmetro é para analisar uma string, ou seja, você deve fornecer a string nesse formato (por exemplo "5/13/2019"). Nada mais, nenhuma mudança de formato. Ele ainda será exibido como 2019-05-13- ou gerará uma exceção, se df['DOB'].astype(str)contiver item (ns) que não estejam em tal formato, por exemplo, em um formato "2019-05-13".
— MarianD

4

Em comparação com a primeira resposta, recomendarei usar dt.strftime () primeiro, depois pd.to_datetime (). Dessa forma, ainda resultará no tipo de dados datetime.

Por exemplo,

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
Isso não funciona, pelo menos no meu caso. Especificamente, a coluna é convertida para o tipo de dados datetime, mas também os valores são convertidos para o formato original!
— Pária em

Não! Erro de sintaxe (chave faltando), na minha versão do Pandas (0.25.1) outro erro de sintaxe (dt.strftime () - só pode usar acessador .dt com valores datetimelike) - você depende do tipo de dados inerente, mas em diferentes versões de Pandas, os tipos de dados inerentes podem ser diferentes), e uma lógica estranha - por que converter data e hora em string e depois voltar em data e hora ? Veja meu comentário sobre a resposta de rishi jain.
— MarianD

2

Existe uma diferença entre

  • o conteúdo de uma célula de dataframe (um valor binário) e
  • sua apresentação (exibindo-o) para nós, humanos.

Portanto, a questão é: como chegar à apresentação adequada dos meus dados sem alterar os próprios dados / tipos de dados?

Aqui está a resposta:

  • Se você usar o notebook Jupyter para exibir seu dataframe, ou
  • se você deseja obter uma apresentação na forma de um arquivo HTML (mesmo com muitos supérfluos ide classatributos preparados para um estilo CSS adicional - você pode ou não usá-los),

usar estilo .O estilo não altera os dados / tipos de dados das colunas do seu dataframe.

Agora vou mostrar como fazer isso no bloco de notas Jupyter - para uma apresentação na forma de arquivo HTML, veja a nota no final da pergunta.

Suponho que sua coluna DOB já tenha o tipodatetime64 (você mostrou que sabe como chegar). Eu preparei um dataframe simples (com apenas uma coluna) para mostrar alguns estilos básicos:

  • Sem estilo:

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

Seja cuidadoso!
O objeto de retorno NÃO é um dataframe - é um objeto da classe Styler, portanto , não o atribua de volta a df:

Não faça isso:

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

(Cada dataframe tem seu objeto Styler acessível por sua .stylepropriedade, e mudamos esse df.styleobjeto, não o próprio dataframe.)


Perguntas e respostas:

  • P: Por que seu objeto Styler (ou uma expressão que o retorna) usado como o último comando em uma célula do bloco de notas Jupyter exibe sua tabela (estilizada) e não o próprio objeto Styler?

  • R: Porque cada objeto Styler tem um método de retorno de chamada ._repr_html_()que retorna um código HTML para renderizar seu dataframe (como uma boa tabela HTML).

    O Jupyter Notebook IDE chama esse método automaticamente para renderizar objetos que o possuem.


Nota:

Você não precisa do notebook Jupyter para estilizar (ou seja, para gerar um quadro de dados sem alterar seus tipos de dados / dados ).

Um objeto Styler também tem um método render(), se você quiser obter uma string com o código HTML (por exemplo, para publicar seu dataframe formatado na Web ou simplesmente apresentar sua tabela no formato HTML):

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

Vale a pena ressaltar que o código do estilizador como este deve ser executado, e só tem efeito no notebook Jupyter, e tem efeito zero quando executado no console ou iPython . O OP não especificava "sob Jupyter", então esta pode ou não ser uma solução viável dependendo de sua configuração. Muito código de ciência de dados é copiado e colado e as suposições específicas do Jupyter não são especificadas explicitamente, então as pessoas se perguntam por que o código do estilizador "não funciona" quando executado em seu ambiente (console).
— smci

@smci, não é explicitamente mencionado no segundo parágrafo da minha resposta? Na forma de ifdeclaração condicional , tão conhecida por todos os programadores? - Apesar de tudo obrigado pelo seu comentário, pode ser útil para algumas pessoas.
— MarianD

não, isso é muito obscuro, também enterrado. A pergunta original não supunha nada sobre o Jupyter, e o OP e alguns usuários podem nem mesmo ter o Jupyter disponível para eles. Sua resposta precisaria dizer em negrito sua primeira linha "A abordagem seguinte (estilo) só funciona no notebook Jupyter e não terá nenhum efeito quando executada fora do notebook Jupyter" . (Em blogs e sites de ciência de dados, vejo diariamente pessoas postando código Jupyter em ambientes não Jupyter e se perguntando por que ele não funciona).
— smci

Legal. Eu também sugiro que você adicione todas as (muitas) armadilhas que você identificou nas outras abordagens de "converter para string-com-strftime-então-voltar-com-pd.to_datetime". Pelo menos, é preciso mencionar o levantamento e a captura de exceções. Além disso, pd.to_datetime()tem os argumentos errors='raise'/'coerce'/'ignore', dayfirst, yearfirst, utc, exactpara controlar o quão preciso e tolerante a exceções ele é, e se saídas inválidas são coagidas NaTou não. O que o torna mais complicado em conjuntos de dados do "mundo real" são os formatos, horários, fusos horários mistos / ausentes / incompletos, etc; exceções não são necessariamente coisas ruins.
— smci

... ou então posso escrever isso como um acúmulo de armadilhas nas abordagens não-Jupyter.
— smci

1

O código abaixo muda para o tipo 'data e hora' e também para formatos na string de formato fornecida. Funciona bem!

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

2
mude para este:df['DOB']=pd.to_datetime(df['DOB']).dt.strftime('%m/%d/%Y')
— John Doe

Não! - Por que converter datetime para string e depois de volta para datetime ? Veja meus comentários para outras respostas.
— MarianD

1

Você pode tentar isso para converter o formato de data para DD-MM-AAAA:

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

Não! dayfirst=Trueé apenas a especificação de uma ordem de análise de data, por exemplo, aquela string de data ambivalente como "2-1-2019" será analisada como 2 de janeiro de 2019, e não como 1 de fevereiro de 2019. Nada mais, nenhuma alteração para a formatação de saída .
— MarianD
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.