2015-04-26 283 views
9

我讀了巨大CSV與日期字段格式爲YYYYMMDD,我用下面的λ將其轉換閱讀時:熊貓:慢日期轉換

import pandas as pd 

df = pd.read_csv(filen, 
       index_col=None, 
       header=None, 
       parse_dates=[0], 
       date_parser=lambda t:pd.to_datetime(str(t), 
              format='%Y%m%d', coerce=True)) 

這個功能是很慢的,雖然。

任何改善它的建議嗎?

回答

34

嘗試使用此功能解析日期:

def lookup(s): 
    """ 
    This is an extremely fast approach to datetime parsing. 
    For large data, the same dates are often repeated. Rather than 
    re-parse these, we store all unique dates, parse them, and 
    use a lookup to convert all dates. 
    """ 
    dates = {date:pd.to_datetime(date) for date in s.unique()} 
    return s.map(dates) 

這樣使用它:

df['date-column'] = lookup(df['date-column']) 

基準:

$ python date-parse.py 
to_datetime: 5799 ms 
dateutil: 5162 ms 
strptime: 1651 ms 
manual:  242 ms 
lookup:  32 ms 

來源:https://github.com/sanand0/benchmarks/tree/master/date-parse

+0

NaN出現問題:'return s.apply(lambda v:dates [v]) KeyError:nan' – ppaulojr

+0

奇怪,我無法重現它,我們可以看到你傳遞給函數的序列?你的Pandas版本是什麼? – fixxxer

+0

哇:這是超級!我有1M行測試文件,它需要1秒鐘的時間來閱讀(無日期解析),但是如果我打開parse_dates,則需要1分20秒。 0.4秒到最初的1秒read_csv()。 – jdmarino

2

嘗試標準庫:

import datetime 
parser = lambda t: datetime.datetime.strptime(str(t), "%Y%m%d") 

不過,我真的不知道這是比大熊貓要快得多。

由於您的格式就是這麼簡單,大約

def parse(t): 
    string_ = str(t) 
    return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:])) 

編輯你說你需要採取無效數據的關心。

def parse(t): 
    string_ = str(t) 
    try: 
     return datetime.date(int(string_[:4]), int(string[4:6]), int(string[6:])) 
    except: 
     return default_datetime #you should define that somewhere else 

所有的一切,我有點矛盾關於你的問題的有效性:

  • 你需要要快,但你仍然從CSV
  • 你需要得到你的數據要快,但仍然需要處理無效數據

這有點矛盾;我個人在這裏的做法是假設你的「巨大的」CSV只需要被引入一次性能更好的格式,而且你不應該關心轉換過程的速度(因爲它只發生一次),或者你可能應該將任何生成的CSV帶給你更好的數據 - 有很多不依賴於字符串解析的格式。

+0

不幸的是,它在某些行中的無效日期效果不好(我不確定如何使用您的方法強制執行 – ppaulojr

+0

您沒有提到您需要處理無效數據;這有點兒不公平的問題 –

1

無需指定date_parser,大熊貓能夠解析這個沒有任何麻煩,再加上它會快很多:

In [21]: 

import io 
import pandas as pd 
t="""date,val 
20120608,12321 
20130608,12321 
20140308,12321""" 
df = pd.read_csv(io.StringIO(t), parse_dates=[0]) 
df.info() 
<class 'pandas.core.frame.DataFrame'> 
Int64Index: 3 entries, 0 to 2 
Data columns (total 2 columns): 
date 3 non-null datetime64[ns] 
val  3 non-null int64 
dtypes: datetime64[ns](1), int64(1) 
memory usage: 72.0 bytes 
In [22]: 

df 
Out[22]: 
     date val 
0 2012-06-08 12321 
1 2013-06-08 12321 
2 2014-03-08 12321 
+1

它可以工作,但速度很慢。 – ppaulojr

+1

嘗試將此添加到'read_csv':'infer_datetime_format = True' – EdChum

+1

是不是推斷會讓事情變得更慢? –

4

偉大的建議@EdChum!正如@EdChum所示,使用infer_datetime_format=True可以使顯着提高。以下是我的例子。

我有溫度數據的文件從一個傳感器日誌,它看起來像這樣:

RecNum,Date,LocationID,Unused 
1,11/7/2013 20:53:01,13.60,"117","1", 
2,11/7/2013 21:08:01,13.60,"117","1", 
3,11/7/2013 21:23:01,13.60,"117","1", 
4,11/7/2013 21:38:01,13.60,"117","1", 
... 

我的代碼讀取CSV和解析日期(parse_dates=['Date'])。 隨着infer_datetime_format=False,它需要8分鐘8秒

Tue Jan 24 12:18:27 2017 - Loading the Temperature data file. 
Tue Jan 24 12:18:27 2017 - Temperature file is 88.172 MB. 
Tue Jan 24 12:18:27 2017 - Loading into memory. Please be patient. 
Tue Jan 24 12:26:35 2017 - Success: loaded 2,169,903 records. 

隨着infer_datetime_format=True,它需要13sec

Tue Jan 24 13:19:58 2017 - Loading the Temperature data file. 
Tue Jan 24 13:19:58 2017 - Temperature file is 88.172 MB. 
Tue Jan 24 13:19:58 2017 - Loading into memory. Please be patient. 
Tue Jan 24 13:20:11 2017 - Success: loaded 2,169,903 records. 
3

流線型日期解析與緩存

讀取所有數據,然後將其轉換在閱讀CSV時總是比轉換慢。因爲如果你馬上做,你不需要遍歷所有的數據兩次。您也不必將其作爲字符串存儲在內存中。

我們可以定義我們自己的日期解析器,該日期解析器利用它已經看到的日期的緩存。

import pandas as pd 

cache = {} 

def cached_date_parser(s): 
    if s in cache: 
     return cache[s] 
    dt = pd.to_datetime(s, format='%Y%m%d', coerce=True) 
    cache[s] = dt 
    return dt 

df = pd.read_csv(filen, 
       index_col=None, 
       header=None, 
       parse_dates=[0], 
       date_parser=cached_date_parser) 

具有相同的優勢@fixxxer s的唯一的解析每個串一次,不必讀取所有數據,然後分析它的額外加分的答案。節省你的記憶和處理時間。