有没有办法在秒 - 过 - 午夜记录中加速日期解析器?

时间:2015-07-18 21:45:00

标签: python pandas python-multiprocessing

假设我在str列中有以下数据集,其日期(date_str)和int列中午夜(seconds_past_midnight)之后的秒数。我想根据这两列的组合来解析日期时间。

import pandas as pd
import numpy as np

n = 1000000
df = pd.DataFrame({'seconds_past_midnight': np.random.randint(34200, 57601, size=n), 'date_str': ['2015-07-14']*n})

print(df)

          date_str  seconds_past_midnight
0       2015-07-14                  48642
1       2015-07-14                  39170
2       2015-07-14                  43940
3       2015-07-14                  46927
4       2015-07-14                  55376
5       2015-07-14                  35859
6       2015-07-14                  38705
7       2015-07-14                  35932
8       2015-07-14                  36874
9       2015-07-14                  39487
...            ...                    ...
999990  2015-07-14                  54837
999991  2015-07-14                  47146
999992  2015-07-14                  54188
999993  2015-07-14                  54729
999994  2015-07-14                  35574
999995  2015-07-14                  35815
999996  2015-07-14                  38727
999997  2015-07-14                  38374
999998  2015-07-14                  53055
999999  2015-07-14                  43303

[1000000 rows x 2 columns]

print(df.dtypes)

date_str                 object
seconds_past_midnight     int64
dtype: object

我能想到的最简单的方法是根据这些秒数构造pd.Timedelta并将它们添加到日期对象中,但是当使用pd.Timedelta时,这基本上是一个行循环for循环做转换,这是非常缓慢的。

%time df.apply(lambda row: pd.to_datetime(row.date_str) + pd.Timedelta(row.seconds_past_midnight, 's'), axis=1)


CPU times: user 2min 5s, sys: 311 ms, total: 2min 5s
Wall time: 2min 5s

所以我想知道是否有办法加速这个过程?也许是我不知道的日期时间对象上的一些矢量化函数?我认为稍微提高速度的一种方法是使用multiprocessing模块,也许我可以期望在8核PC上快4-6倍。另外,因为我在apply中调用python函数,在这种情况下,cython或jit没有帮助吗?

4 个答案:

答案 0 :(得分:2)

padding

答案 1 :(得分:2)

pd.to_datetimepd.to_timedelta都已经过矢量化。

In [13]: np.random.seed(1234)

In [14]: df = pd.DataFrame({'seconds_past_midnight': np.random.randint(34200, 57601, size=n), 'date_str': ['2015-07-14']*n})

In [15]: df.head()
Out[15]: 
     date_str  seconds_past_midnight
0  2015-07-14                  35518
1  2015-07-14                  51248
2  2015-07-14                  56721
3  2015-07-14                  57417
4  2015-07-14                  42671

In [16]: df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 1000000 entries, 0 to 999999
Data columns (total 2 columns):
date_str                 1000000 non-null object
seconds_past_midnight    1000000 non-null int64
dtypes: int64(1), object(1)
memory usage: 22.9+ MB

In [17]: (pd.to_datetime(df['date_str']) + pd.to_timedelta(df['seconds_past_midnight'],unit='s')).head()
Out[17]: 
0   2015-07-14 09:51:58
1   2015-07-14 14:14:08
2   2015-07-14 15:45:21
3   2015-07-14 15:56:57
4   2015-07-14 11:51:11
dtype: datetime64[ns]

In [18]: %timeit pd.to_datetime(df['date_str']) + pd.to_timedelta(df['seconds_past_midnight'],unit='s')        
10 loops, best of 3: 187 ms per loop

这是当前的主人,它有几个性能改进。在0.16.2中,这慢了2倍。

答案 2 :(得分:1)

您还可以使用NumPy datetime64's and timedelta64's进行添加:

(np.array(df['date_str'], '<M8[D]') + 
np.array(df['seconds_past_midnight'], dtype='<m8[s]'))

例如,

import pandas as pd
import numpy as np
np.random.seed(1234)

n = 1000000
df = pd.DataFrame({
    'seconds_past_midnight': np.random.randint(34200, 57601, size=n), 
    'date_str': ['2015-07-14']*n})

包含对DataFrame的分配:

In [4]: pd.__version__
Out[6]: u'0.16.2+175.g5a9a9da'

In [7]: %timeit df['date'] = np.array(df['date_str'], '<M8[D]')+np.array(df['seconds_past_midnight'], dtype='<m8[s]')
10 loops, best of 3: 94.6 ms per loop

In [8]: %timeit df['date2'] = pd.to_datetime(df['date_str']) + pd.to_timedelta(df['seconds_past_midnight'],unit='s')  
10 loops, best of 3: 188 ms per loop

In [12]: df['date'].equals(df['date2'])
Out[12]: True

(如果没有赋值给DataFrame,datetime64 / timedelta64 sum会返回一个NumPy数组,而to_datetime/to_timedelta之和会返回一个Pandas系列,因此比较这些将是一个苹果与橙子的比较。)

答案 3 :(得分:0)

你可以解析strptime(“%Y-%m-%d%f”),%f在技术上是微秒,不知道这有用吗?