2013-01-04 20 views
8

Mam pliki danych zawierające listy ciągów reprezentujących daty w formacie ISO. Obecnie czytam je w użyciu:Konwertuj listę datestrings na datetime bardzo wolno z Python strptime

mydates = [ datetime.datetime.strptime(timdata[x], "%Y-%m-%dT%H:%M:%S") for x in range(len(timedata)) ] 

Wygląda to dość proste, ale jest śmiesznie powolny podczas pracy na ogromnych list ~ 25000 datami -> O 0.34 sekund na przebudowanej listy. Ponieważ mam tysiące takich list, szukam szybszego sposobu. Jednak nie udało mi się jeszcze tego znaleźć. Parser dateutil wykonuje jeszcze gorsze ...

+3

Masz na myśli, że analizowanie i konwersja 25 000 dat, w tym tworzenie nowej listy o tym samym rozmiarze, powinno być szybsze niż jedna trzecia sekundy w języku interpretowanym? Możesz przełączyć się na skompilowany język. –

+1

@TimPietzcker Możesz czytać i parsować plik zawierający więcej niż 25000 dat i 10 dodatkowych kolumn w mniej niż jedną trzecią sekundy z numpy/pandas. – bmu

+0

Tego też doświadczyłem ... – HyperCube

Odpowiedz

8

indeksowania/krojenie wydaje się być szybszy niż regex używane przez @NPE:

In [47]: def with_indexing(dstr):        
    ....:  return datetime.datetime(*map(int, [dstr[:4], dstr[5:7], dstr[8:10], 
    ....:        dstr[11:13], dstr[14:16], dstr[17:]])) 

In [48]: p = re.compile('[-T:]') 

In [49]: def with_regex(dt_str): 
    ....:  return datetime.datetime(*map(int, p.split(dt_str))) 

In [50]: %timeit with_regex(dstr) 
100000 loops, best of 3: 3.84 us per loop 

In [51]: %timeit with_indexing(dstr) 
100000 loops, best of 3: 2.98 us per loop 

Myślę, że jeśli użyjesz parsera plików, takiego jak numpy.genfromtxt, argumentu converters i metody szybkiego parsowania, możesz przeczytać i przeanalizować cały plik w mniej niż pół sekundy.

użyłem następującą funkcję tworzenia pliku Przykład z około 25000 wierszy, łańcuchach daty ISO jak indeksie i 10 kolumn danych:

import numpy as np 
import pandas as pd 

def create_data(): 
    # create dates 
    dates = pd.date_range('2010-01-01T00:30', '2013-01-04T23:30', freq='H') 
    # convert to iso 
    iso_dates = dates.map(lambda x: x.strftime('%Y-%m-%dT%H:%M:%S')) 
    # create data 
    data = pd.DataFrame(np.random.random((iso_dates.size, 10)) * 100, 
         index=iso_dates) 
    # write to file 
    data.to_csv('dates.csv', header=False) 

niż kiedyś następujący kod do analizowania pliku:

In [54]: %timeit a = np.genfromtxt('dates.csv', delimiter=',', 
            converters={0:with_regex}) 
1 loops, best of 3: 430 ms per loop 

In [55]: %timeit a = np.genfromtxt('dates.csv', delimiter=',', 
            converters={0:with_indexing}) 
1 loops, best of 3: 391 ms per loop 

pandas (na podstawie numpy) w którym C podstawie pliku parser który jest jeszcze szybszy:

In [56]: %timeit df = pd.read_csv('dates.csv', header=None, index_col=0, 
            parse_dates=True, date_parser=with_indexing) 
10 loops, best of 3: 167 ms per loop 
+0

Dziękuję za dopracowaną odpowiedź. To bardzo pomaga! – HyperCube

15

Oto sposób, aby zrobić to około 3 razy szybciej.

Oryginalna wersja:

In [23]: %timeit datetime.datetime.strptime("2013-01-01T01:23:45", "%Y-%m-%dT%H:%M:%S") 
10000 loops, best of 3: 21.8 us per loop 

Szybsza wersja:

In [24]: p = re.compile('[-T:]') 

In [26]: %timeit datetime.datetime(*map(int, p.split("2013-01-01T01:23:45"))) 
100000 loops, best of 3: 7.28 us per loop 

To oczywiście nie aż tak elastyczny jak strptime().

edit: Używając jednego regex wyodrębnić składniki data jest nieznacznie szybciej:

In [48]: pp = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})') 

In [49]: %timeit datetime.datetime(*map(int, pp.match("2013-01-01T01:23:45").groups())) 
100000 loops, best of 3: 6.92 us per loop 
+0

Dzięki za szybką reakcję! 3 razy szybciej to znaczna poprawa !! :) – HyperCube