I panda possono riconoscere automaticamente le date?


151

Oggi sono rimasto positivamente sorpreso dal fatto che durante la lettura dei dati da un file di dati (ad esempio) Panda sia in grado di riconoscere tipi di valori:

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

Ad esempio, può essere verificato in questo modo:

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

In particolare numeri interi, float e stringhe sono stati riconosciuti correttamente. Tuttavia, ho una colonna che ha date nel seguente formato: 2013-6-4. Queste date sono state riconosciute come stringhe (non come oggetti data Python). C'è un modo per "imparare" i panda a date riconosciute?


Si prega di indicare sempre la versione di Panda, per questo tipo di domanda dipendente dalla versione. Nel luglio 2013, questo sarebbe stato il v0.11
smci il

E i tipi sono fissi per ogni colonna, non è necessario ripetere l'iterazione df.iterrows()e visualizzarli per ogni singola riga, basta fare df.info()una volta.
smci,

Risposte:


327

Dovresti aggiungere parse_dates=True, o parse_dates=['column name']durante la lettura, che di solito è abbastanza per analizzarlo magicamente. Ma ci sono sempre formati strani che devono essere definiti manualmente. In tal caso è anche possibile aggiungere una funzione di analisi della data, che è il modo più flessibile possibile.

Supponiamo di avere una colonna 'datetime' con la tua stringa, quindi:

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

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

In questo modo puoi anche combinare più colonne in una singola colonna datetime, questo unisce una colonna 'data' e una 'ora' in una singola colonna '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)

Puoi trovare le direttive (ovvero le lettere da utilizzare per diversi formati) per strptimee strftime in questa pagina .


8
Non ha funzionato per me, ho riscontrato il seguente errore:TypeError: strptime() argument 1 must be str, not float
Jean Paul,

6
Ho avuto questo errore perché c'erano nan nel mio frame di dati.
Jean Paul,

puoi aggiungere un elemento che NaTs anche il materiale non analizzabile o NaN o / Ns. perché sembra che questo parser salti completamente l'intera colonna se è presente qualcosa del genere
Amir,

C'è un'opzione infer_datetime_format: "i panda tenteranno di inferire il formato delle stringhe datetime nelle colonne". Questo può essere usato al posto di date_parser.
Vinci il

1
Nota che se le tue date sono in ISO 8601formato non dovresti passare infer_datetime_formato una funzione di analisi - è molto più lento che lasciare che i panda la gestiscano (specialmente quest'ultima). Il formato data in questa risposta rientra anche in questa categoria
Mr_and_Mrs_D

20

Forse l'interfaccia di Panda è cambiata da quando ha risposto @Rutger, ma nella versione che sto usando (0.15.2), la date_parserfunzione riceve un elenco di date anziché un singolo valore. In questo caso, il suo codice dovrebbe essere aggiornato in questo modo:

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

Il metodo panda read_csv è ottimo per l'analisi delle date. Documentazione completa su http://pandas.pydata.org/pandas-docs/stable/generated/pandas.io.parsers.read_csv.html

puoi anche avere le diverse parti della data in colonne diverse e passare il parametro:

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

Il rilevamento predefinito delle date funziona alla grande, ma sembra essere distorto verso i formati di data nordamericani. Se vivi altrove, potresti essere occasionalmente sorpreso dai risultati. Per quanto posso ricordare, 1/6/2000 significa il 6 gennaio negli Stati Uniti invece del 1 giugno in cui vivo. È abbastanza intelligente ruotarli se si usano date come il 23/06/2000. Probabilmente è più sicuro rimanere con le variazioni di data AAAAMMGG. Mi scuso con gli sviluppatori di Panda, qui ma non l'ho testato di recente con date locali.

puoi usare il parametro date_parser per passare una funzione per convertire il tuo 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
È possibile specificare dayfirstcome True per le date europee / internazionali. pandas.pydata.org/pandas-docs/stable/generated/…
Will Gordon

10

È possibile utilizzare pandas.to_datetime()come raccomandato nella documentazione per pandas.read_csv():

Se una colonna o un indice contiene una data non analizzabile, l'intera colonna o indice verrà restituito inalterato come tipo di dati oggetto. Per l'analisi datetime non standard, utilizzare 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

sta convertendo anche altre colonne fino ad oggi, che sono di tipo oggetto
ratnesh

10

Quando si uniscono due colonne in una singola colonna datetime, la risposta accettata genera un errore (panda versione 0.20.3), poiché le colonne vengono inviate separatamente alla funzione date_parser.

Le seguenti opere:

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
Sto usando Panda 0.22 e sono d'accordo che la risposta accettata non funziona più.
Dai,

Questo crea un "TypeError: può concatenare solo str (non" float ") in str" per me. La colonna della data è d / m / y e la colonna dell'ora è H: M: 00
IceQueeny,

8

Sì - secondo la pandas.read_csv documentazione :

Nota: esiste un percorso rapido per le date in formato iso8601 .

Quindi, se il tuo CSV ha una colonna denominata datetimee le date sembrano come 2013-01-01T01:01ad esempio, l'esecuzione di questo panda farà sì che i panda (io sono su v0.19.2) raccolgano automaticamente la data e l'ora:

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

Si noti che è necessario passare esplicitamente parse_dates, non funziona senza.

Verifica con:

df.dtypes

Dovresti vedere il tipo di dati della colonna datetime64[ns]


Penso che tu abbia frainteso la domanda. L'utente è curioso di sapere se l'opzione potrebbe essere abilitata per il suo formato di stringa.
Arya McCarthy,

@AryaMcCarthy umm, fondamentalmente vuole che la data venga riconosciuta correttamente, quindi sto menzionando come può trasformare i dati di origine in modo che siano naturalmente riconosciuti dai panda. Da nessuna parte dice che non può cambiare il formato dei dati di origine.
Gaurav,

1

Se le prestazioni contano per te, assicurati di avere il 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)')

stampe:

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

Quindi, con ISO8601-formattato data ( %Y-%m-%d %H:%M:%Sè apparentemente una data ISO8601-formattato, credo che il T può essere eliminato e sostituito da uno spazio) si dovrebbe non specifica infer_datetime_format(che non fa la differenza con quelli più comuni sia apparentemente) e passando il proprio parser in prestazioni da paralizzare. D'altra parte, date_parserfa la differenza con formati giorno non così standard. Assicurati di prendere tempo prima di ottimizzare, come al solito.


1

Durante il caricamento del file CSV contiene la colonna della data. Abbiamo due approcci per fare in modo che i panda riconoscano la colonna della data, ad es

  1. I panda riconoscono esplicitamente il formato dall'arg date_parser=mydateparser

  2. I panda impliciti riconoscono il formato da agr infer_datetime_format=True

Alcuni dei dati della colonna della data

01/01/18

01/02/18

Qui non conosciamo le prime due cose Potrebbe essere mese o giorno. Quindi in questo caso dobbiamo usare il Metodo 1: - Passare esplicitamente il 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)

Metodo 2: - Implicito o Riconoscimento automatico del formato

df = pd.read_csv(file_name, parse_dates=[date_col_name],infer_datetime_format=True)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.