Os pandas podem reconhecer datas automaticamente?


151

Hoje, fiquei positivamente surpreso pelo fato de que, ao ler dados de um arquivo de dados (por exemplo), o pandas é capaz de reconhecer tipos de valores:

df = pandas.read_csv('test.dat', delimiter=r"\s+", names=['col1','col2','col3'])

Por exemplo, pode ser verificado desta maneira:

for i, r in df.iterrows():
    print type(r['col1']), type(r['col2']), type(r['col3'])

Em particular inteiro, flutuadores e seqüências de caracteres foram reconhecidos corretamente. No entanto, tenho uma coluna que tem datas no seguinte formato: 2013-6-4. Essas datas foram reconhecidas como seqüências de caracteres (não como objetos de data python). Existe uma maneira de "aprender" pandas para datas reconhecidas?


Sempre indique a versão do pandas para esse tipo de pergunta dependente da versão. Em julho de 2013, isso teria sido v0.11
smci

E os tipos são corrigidos para cada coluna; você não precisa iterar df.iterrows()e visualizá-los para cada linha, apenas df.info()uma vez.
smci 20/04

Respostas:


326

Você deve adicionar parse_dates=True, ou parse_dates=['column name']ao ler, isso geralmente é suficiente para analisá-lo magicamente. Mas sempre existem formatos estranhos que precisam ser definidos manualmente. Nesse caso, você também pode adicionar uma função de analisador de datas, que é a maneira mais flexível possível.

Suponha que você tenha uma coluna 'datetime' com sua string, então:

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

Dessa forma, você pode até combinar várias colunas em uma única coluna de data e hora; isso mescla uma coluna 'date' e 'time' em uma única coluna 'datetime':

dateparse = lambda x: pd.datetime.strptime(x, '%Y-%m-%d %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

Você pode encontrar diretrizes (ou seja, as letras a serem usadas para diferentes formatos) para strptimee strftime nesta página .


8
Não funcionou para mim, recebi o seguinte erro:TypeError: strptime() argument 1 must be str, not float
Jean Paul

6
Eu recebi esse erro porque havia nan no meu quadro de dados.
21419 Jean Paul

você pode adicionar um item que também NaTs o material não analisável ou NaN ou / Ns. causa parece que este analisador ignora totalmente toda a coluna, se nada disso está presente
Amir

Existe uma opção infer_datetime_format: "os pandas tentarão inferir o formato das seqüências de data e hora nas colunas". Isso pode ser usado em vez de date_parser.
Winand

1
Observe que, se suas datas estiverem no ISO 8601formato, você não deve passar infer_datetime_formatou uma função de analisador - é muito mais lento do que permitir que os pandas lidem com isso (especialmente o último). O formato da data nesta resposta também se enquadra nessa categoria
Mr_and_Mrs_D

20

Talvez a interface do pandas tenha mudado desde que o @Rutger respondeu, mas na versão que estou usando (0.15.2), a date_parserfunção recebe uma lista de datas em vez de um único valor. Nesse caso, seu código deve ser atualizado da seguinte maneira:

dateparse = lambda dates: [pd.datetime.strptime(d, '%Y-%m-%d %H:%M:%S') for d in dates]

df = pd.read_csv(infile, parse_dates=['datetime'], date_parser=dateparse)

11

O método read_csv do pandas é ótimo para analisar datas. Documentação completa em http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

você pode até ter partes diferentes da data em colunas diferentes e passar o parâmetro:

parse_dates : boolean, list of ints or names, list of lists, or dict
If True -> try parsing the index. If [1, 2, 3] -> try parsing columns 1, 2, 3 each as a
separate date column. If [[1, 3]] -> combine columns 1 and 3 and parse as a single date
column. {‘foo : [1, 3]} -> parse columns 1, 3 as date and call result foo

O sensor padrão de datas funciona muito bem, mas parece estar inclinado para os formatos de data norte-americanos. Se você mora em outro lugar, ocasionalmente pode ser pego pelos resultados. Tanto quanto me lembro, 1/6/2000 significa 6 de janeiro nos EUA, e não 1 de junho, onde moro. É inteligente o suficiente para alterá-los se datas como 23/6/2000 forem usadas. Provavelmente, é mais seguro permanecer com as variações de data AAAAMMDD. Desculpas aos desenvolvedores de pandas, aqui, mas eu não testei com datas locais recentemente.

você pode usar o parâmetro date_parser para passar uma função para converter seu formato.

date_parser : function
Function to use for converting a sequence of string columns to an array of datetime
instances. The default uses dateutil.parser.parser to do the conversion.

2
Você pode especificar dayfirstcomo Verdadeiro para datas europeias / internacionais. pandas.pydata.org/pandas-docs/stable/generated/…
Will Gordon

10

Você pode usar pandas.to_datetime()como recomendado na documentação para pandas.read_csv():

Se uma coluna ou índice contiver uma data não analisável, a coluna ou o índice inteiro será retornado inalterado como um tipo de dados do objeto. Para análise de data e hora não padrão, use pd.to_datetimeafter pd.read_csv.

Demo:

>>> D = {'date': '2013-6-4'}
>>> df = pd.DataFrame(D, index=[0])
>>> df
       date
0  2013-6-4
>>> df.dtypes
date    object
dtype: object
>>> df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
>>> df
        date
0 2013-06-04
>>> df.dtypes
date    datetime64[ns]
dtype: object

também está convertendo outras colunas para data, que são do tipo de objeto
ratnesh

10

Ao mesclar duas colunas em uma única coluna de data e hora, a resposta aceita gera um erro (pandas versão 0.20.3), pois as colunas são enviadas para a função date_parser separadamente.

Os seguintes trabalhos:

def dateparse(d,t):
    dt = d + " " + t
    return pd.datetime.strptime(dt, '%d/%m/%Y %H:%M:%S')

df = pd.read_csv(infile, parse_dates={'datetime': ['date', 'time']}, date_parser=dateparse)

1
Estou usando pandas 0.22 e concordo que a resposta aceita não funciona mais.
Dai

Isso cria um "TypeError: só pode concatenar str (não" float ") para str" para mim. A coluna de data é d / m / y e a coluna de tempo é H: M: 00
IceQueeny 27/10

8

Sim - de acordo com a pandas.read_csv documentação :

Nota: Existe um caminho rápido para datas no formato iso8601 .

Portanto, se o seu csv tiver uma coluna chamada datetimee as datas 2013-01-01T01:01parecerem, por exemplo, executar isso fará com que os pandas (eu esteja na v0.19.2) selecionem a data e a hora automaticamente:

df = pd.read_csv('test.csv', parse_dates=['datetime'])

Observe que você precisa passar explicitamente parse_dates; ele não funciona sem.

Verifique com:

df.dtypes

Você deve ver que o tipo de dados da coluna é datetime64[ns]


Eu acho que você não entendeu a pergunta. O usuário está curioso para saber se a opção pode ser ativada para seu formato de sequência.
Arya McCarthy

@AryaMcCarthy umm, ele basicamente quer que a data seja reconhecida corretamente, então estou mencionando como ele pode transformar os dados de origem para que sejam naturalmente reconhecidos pelos pandas. Em nenhum lugar ele menciona que não pode alterar o formato dos dados de origem.
Gaurav

1

Se o desempenho é importante para você, certifique-se de tempo:

import sys
import timeit
import pandas as pd

print('Python %s on %s' % (sys.version, sys.platform))
print('Pandas version %s' % pd.__version__)

repeat = 3
numbers = 100

def time(statement, _setup=None):
    print (min(
        timeit.Timer(statement, setup=_setup or setup).repeat(
            repeat, numbers)))

print("Format %m/%d/%y")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,07/29/15
x2,07/29/15
x3,07/29/15
x4,07/30/15
x5,07/29/15
x6,07/29/15
x7,07/29/15
y7,08/05/15
x8,08/05/15
z3,08/05/15
''' * 100)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%m/%d/%y")); data.seek(0)')

print("Format %Y-%m-%d %H:%M:%S")
setup = """import pandas as pd
import io

data = io.StringIO('''\
ProductCode,Date
''' + '''\
x1,2016-10-15 00:00:43
x2,2016-10-15 00:00:56
x3,2016-10-15 00:00:56
x4,2016-10-15 00:00:12
x5,2016-10-15 00:00:34
x6,2016-10-15 00:00:55
x7,2016-10-15 00:00:06
y7,2016-10-15 00:00:01
x8,2016-10-15 00:00:00
z3,2016-10-15 00:00:02
''' * 1000)"""

time('pd.read_csv(data); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"]); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'infer_datetime_format=True); data.seek(0)')
time('pd.read_csv(data, parse_dates=["Date"],'
     'date_parser=lambda x: pd.datetime.strptime(x, "%Y-%m-%d %H:%M:%S")); data.seek(0)')

impressões:

Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28) 
[Clang 6.0 (clang-600.0.57)] on darwin
Pandas version 0.23.4
Format %m/%d/%y
0.19123052499999993
8.20691274
8.143124389
1.2384357139999977
Format %Y-%m-%d %H:%M:%S
0.5238807110000039
0.9202787830000005
0.9832778819999959
12.002349824999996

Portanto, com a data no formato iso8601 ( %Y-%m-%d %H:%M:%Saparentemente é uma data no formato iso8601, acho que o T pode ser descartado e substituído por um espaço), você não deve especificar infer_datetime_format(o que não faz diferença nos mais comuns, aparentemente) e passar o seu próprio analisador em apenas prejudica o desempenho. Por outro lado, date_parserfaz a diferença com formatos de dia não tão comuns. Certifique-se de tempo antes de otimizar, como de costume.


1

Ao carregar o arquivo csv contém a coluna de data. Temos duas maneiras de fazer os pandas reconhecerem a coluna de data, ou seja,

  1. Pandas explicitamente reconhecem o formato por arg date_parser=mydateparser

  2. Os pandas implícitos reconhecem o formato por infer_datetime_format=True

Alguns dos dados da coluna de data

01/01/18

01/02/18

Aqui não sabemos as duas primeiras coisas. Pode ser mês ou dia. Portanto, neste caso, temos que usar o método 1: - Passagem explícita do formato

    mydateparser = lambda x: pd.datetime.strptime(x, "%m/%d/%y")
    df = pd.read_csv(file_name, parse_dates=['date_col_name'],
date_parser=mydateparser)

Método 2: - Implícito ou reconhecer automaticamente o formato

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
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.