2013-01-21 12 views
7

Ben şuna benzer muazzam dosyaları var:Hız geliştirme datetime indeksi ile read_csv

05/31/2012,15: 30: 00.029,1306.25,1, E, 0, 1306,25

05/31/2012,15: 30: verimli etmek

pd.read_csv(gzip.open("myfile.gz"), header=None,names= 
    ["date","time","price","size","type","zero","empty","last"], parse_dates=[[0,1]]) 

mi var herhangi bir şekilde: 00.029,1306.25,8, E, 0, 1306,25

kolayca aşağıdaki kullanarak bunları okuyabilir Böyle tarihler pandalar zaman damgaları içine ayrıştırır? Değilse, date_parser = 'a geçebilecek bir cython işlevi yazmak için herhangi bir kılavuz var mı?

Kendi çözümleyici işlevimi yazmayı denedim ve üzerinde çalıştığım proje için hala çok uzun sürüyor. ([ "Tarihi"] değerlere df, df [ "zaman"] değerleri..)

zaman damgaları = convert_date_cython: python

çağrı:

+0

Yani read_csv işlevi ayrıştırma ihtiyaçlarını karşılayan ama çok yavaş? – BKay

+0

Evet, aslında. Kolay bir çözüm yoksa, birisinin bunu cython'da ele almak için kılavuzluk edip edemeyeceğini görmek istedim. –

+0

"pd.Timestamp" ın çalışmadığı (örneğin pd.Timestamp ('05 /31/2012,15:30:00.029 ') 'ile birlikte) bunu karıştırıyor. Olmadığı gerçeği büyük ihtimalle bir böcek. –

cevap

6

önceki solution of Michael WS bir gelişme:

  • dönüşüm pandas.Timestamp için Cython kodu dışında gerçekleştirmek için daha da
  • atoi ve işleme doğal-c dizeleri az biraz daha hızlı piton funcs daha
  • 2 (+1 tarih zaman)
  • mikro da
  • işlenir gelen bir düşürülür aramaları -lib datetime sayısı

NB! Bu koddaki tarih sırası gün/ay/yıl'dır. tüm kodunda

Tüm

orijinal yaklaşık olarak 10 kat daha hızlı gibi görünüyor. Bu zor fark sürücü SSD sonra read_csv sonra denir Ancak eğer toplam zaman okuma yükü nedeniyle sadece birkaç yüzdeleri olmasıdır. Normal HDD'de farkın daha da küçük olacağını tahmin ediyorum.

cimport numpy as np 
import datetime 
import numpy as np 
import pandas as pd 
from libc.stdlib cimport atoi, malloc, free 
from libc.string cimport strcpy 

### Modified code from Michael WS: 
### https://stackoverflow.com/a/15812787/2447082 

def convert_date_fast(np.ndarray date_vec, np.ndarray time_vec): 
    cdef int i, d_year, d_month, d_day, t_hour, t_min, t_sec, t_ms 
    cdef int N = len(date_vec) 
    cdef np.ndarray out_ar = np.empty(N, dtype=np.object) 
    cdef bytes prev_date = <bytes> 'xx/xx/xxxx' 
    cdef char *date_str = <char *> malloc(20) 
    cdef char *time_str = <char *> malloc(20) 

    for i in range(N): 
     if date_vec[i] != prev_date: 
      prev_date = date_vec[i] 
      strcpy(date_str, prev_date) ### xx/xx/xxxx 
      date_str[2] = 0 
      date_str[5] = 0 
      d_year = atoi(date_str+6) 
      d_month = atoi(date_str+3) 
      d_day = atoi(date_str) 

     strcpy(time_str, time_vec[i]) ### xx:xx:xx:xxxxxx 
     time_str[2] = 0 
     time_str[5] = 0 
     time_str[8] = 0 
     t_hour = atoi(time_str) 
     t_min = atoi(time_str+3) 
     t_sec = atoi(time_str+6) 
     t_ms = atoi(time_str+9) 

     out_ar[i] = datetime.datetime(d_year, d_month, d_day, t_hour, t_min, t_sec, t_ms) 
    free(date_str) 
    free(time_str) 
    return pd.to_datetime(out_ar) 
6

Aşağıdaki Cython kodu ile inanılmaz hızlanma (50X) var
cimport numpy as np 
import pandas as pd 
import datetime 
import numpy as np 
def convert_date_cython(np.ndarray date_vec, np.ndarray time_vec): 
    cdef int i 
    cdef int N = len(date_vec) 
    cdef out_ar = np.empty(N, dtype=np.object) 
    date = None 
    for i in range(N): 
     if date is None or date_vec[i] != date_vec[i - 1]: 
      dt_ar = map(int, date_vec[i].split("/")) 
      date = datetime.date(dt_ar[2], dt_ar[0], dt_ar[1]) 
     time_ar = map(int, time_vec[i].split(".")[0].split(":")) 
     time = datetime.time(time_ar[0], time_ar[1], time_ar[2]) 
     out_ar[i] = pd.Timestamp(datetime.datetime.combine(date, time)) 
    return out_ar 
2

Tarihsel dizgilerin asallığı çok büyük değil. Örneğin, %H-%M-%S biçimindeki zaman dizelerinin sayısı 24 * 60 * 60 = 86400'dur. Veri kümenizin satır sayısı bundan daha büyüktür ya da veri ölçüde hızlandırmak olabilir ayrıştırma sürecinde bir önbellek ekleyerek, yinelenen zaman damgaları sürü içeriyorsa.Cython mevcut olmayan olanlar için

, burada alternatif bir saf Python çözüm: Aşağıdaki belirli veri seti ile

import numpy as np 
import pandas as pd 
from datetime import datetime 


def parse_datetime(dt_array, cache=None): 
    if cache is None: 
     cache = {} 
    date_time = np.empty(dt_array.shape[0], dtype=object) 
    for i, (d_str, t_str) in enumerate(dt_array): 
     try: 
      year, month, day = cache[d_str] 
     except KeyError: 
      year, month, day = [int(item) for item in d_str[:10].split('-')] 
      cache[d_str] = year, month, day 
     try: 
      hour, minute, sec = cache[t_str] 
     except KeyError: 
      hour, minute, sec = [int(item) for item in t_str.split(':')] 
      cache[t_str] = hour, minute, sec 
     date_time[i] = datetime(year, month, day, hour, minute, sec) 
    return pd.to_datetime(date_time) 


def read_csv(filename, cache=None): 
    df = pd.read_csv(filename) 
    df['date_time'] = parse_datetime(df.loc[:, ['date', 'time']].values, cache=cache) 
    return df.set_index('date_time') 

, hızlanma olduğunu 150X +:

ipython olarak
$ ls -lh test.csv 
-rw-r--r-- 1 blurrcat blurrcat 1.2M Apr 8 12:06 test.csv 
$ head -n 4 data/test.csv 
user_id,provider,date,time,steps 
5480312b6684e015fc2b12bc,fitbit,2014-11-02 00:00:00,17:47:00,25 
5480312b6684e015fc2b12bc,fitbit,2014-11-02 00:00:00,17:09:00,4 
5480312b6684e015fc2b12bc,fitbit,2014-11-02 00:00:00,19:10:00,67 

:

Bellek kullanımını sınırlamak için, basitçe bir önbellekle bir şey değiştirin Bir LRU gibi.

+0

yılında hata düzeltildi, onun milisaniye damgalı. Bu çok büyük 15: 30: 00.029 –

+0

@MichaelWS, böylece önbellekte 1k ek öğeler kullanabilirsiniz. – blurrcat