Python Pandas:如何快速创建一个DateTime Index?

5

我的数据看起来是这样的:

TEST
2012-05-01 00:00:00.203 OFF 0
2012-05-01 00:00:11.203 OFF 0
2012-05-01 00:00:22.203 ON 1
2012-05-01 00:00:33.203 ON 1
2012-05-01 00:00:44.203 OFF 0
TEST
2012-05-02 00:00:00.203 OFF 0
2012-05-02 00:00:11.203 OFF 0
2012-05-02 00:00:22.203 OFF 0
2012-05-02 00:00:33.203 ON 1
2012-05-02 00:00:44.203 ON 1
2012-05-02 00:00:55.203 OFF 0

我正在使用 pandasread_table 函数来读取一个预处理过的字符串(已经去掉了“TEST”行),代码如下:
df = pandas.read_table(buf, sep=' ', header=None, parse_dates=[[0, 1]], date_parser=dateParser, index_col=[0])

到目前为止,我尝试了几个日期解析器,其中未被注释的那个是最快的。

def dateParser(s):
#return datetime.strptime(s, "%Y-%m-%d %H:%M:%S.%f")
return datetime(int(s[0:4]), int(s[5:7]), int(s[8:10]), int(s[11:13]), int(s[14:16]), int(s[17:19]), int(s[20:23])*1000)
#return np.datetime64(s)
#return pandas.Timestamp(s, "%Y-%m-%d %H:%M:%S.%f", tz='utc' )

有没有其他方法可以加快速度?我需要读取大量数据 - 每个文件几个GB。


你对数据格式有什么要求吗?也就是说,你是否可以使用制表符分隔的文件,其中日期和时间字段是用空格分隔的? - diliop
@diliop:不,我无法影响输入数据格式。 - user1412286
1个回答

6

简单来说,您指出的将日期/时间字符串解析为datetime-类型索引的最快方法,确实是最快的方法。我测试了一些您的方法和其他方法,以下是我的结果。

首先,获取一个示例DataFrame

import datetime
from pandas import *

start = datetime(2000, 1, 1)
end = datetime(2012, 12, 1)
d = DateRange(start, end, offset=datetools.Hour())
t_df = DataFrame({'field_1': np.array(['OFF', 'ON'])[np.random.random_integers(0, 1, d.size)], 'field_2': np.random.random_integers(0, 1, d.size)}, index=d)

位置:

In [1]: t_df.head()
Out[1]: 
                    field_1  field_2
2000-01-01 00:00:00      ON        1
2000-01-01 01:00:00     OFF        0
2000-01-01 02:00:00     OFF        1
2000-01-01 03:00:00     OFF        1
2000-01-01 04:00:00      ON        1
In [2]: t_df.shape
Out[2]: (113233, 2)

如果您将其转储到磁盘上,则此文件大小约为3.2MB。现在我们需要删除IndexDataRange类型,并将其更改为str列表,以模拟您如何解析数据:

t_df.index = t_df.index.map(str)

如果使用read_table将数据读入DataFrame时,设置parse_dates = True,则平均解析时间为9.5秒

In [3]: import numpy as np
In [4]: import timeit
In [5]: t_df.to_csv('data.tsv', sep='\t', index_label='date_time')
In [6]: t = timeit.Timer("from __main__ import read_table; read_table('data.tsv', sep='\t', index_col=0, parse_dates=True)")
In [7]: np.mean(t.repeat(10, number=1))
Out[7]: 9.5226533889770515

其他策略首先将数据解析成DataFrame(解析时间可以忽略不计),然后将索引转换为datetime对象的Index
In [8]: t = timeit.Timer("from __main__ import t_df, dateutil; map(dateutil.parser.parse, t_df.index.values)")
In [9]: np.mean(t.repeat(10, number=1))
Out[9]: 7.6590064525604244
In [10]: t = timeit.Timer("from __main__ import t_df, dateutil; t_df.index.map(dateutil.parser.parse)")
In [11]: np.mean(t.repeat(10, number=1))
Out[11]: 7.8106775999069216
In [12]: t = timeit.Timer("from __main__ import t_df, datetime; t_df.index.map(lambda x: datetime.strptime(x, \"%Y-%m-%d %H:%M:%S\"))")
Out[12]: 2.0389052629470825
In [13]: t = timeit.Timer("from __main__ import t_df, np; map(np.datetime_, t_df.index.values)")
In [14]: np.mean(t.repeat(10, number=1))
Out[14]: 3.8656840562820434
In [15]: t = timeit.Timer("from __main__ import t_df, np; map(np.datetime64, t_df.index.values)")
In [16]: np.mean(t.repeat(10, number=1))
Out[16]: 3.9244711160659791

现在揭晓获胜者:

In [17]: def f(s):
   ....:         return datetime(int(s[0:4]), 
   ....:                     int(s[5:7]), 
   ....:                     int(s[8:10]), 
   ....:                     int(s[11:13]), 
   ....:                     int(s[14:16]), 
   ....:                     int(s[17:19]))
   ....: t = timeit.Timer("from __main__ import t_df, f; t_df.index.map(f)")
   ....: 
In [18]: np.mean(t.repeat(10, number=1))
Out[18]: 0.33927145004272463

当使用numpypandasdatetime类型的方法时,肯定会有更多的优化需要考虑,但在我看来,最好使用CPython的标准库,将每个日期/时间str转换为一组int,然后再转换为datetime实例,这是获得所需结果的最快方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接