2013-01-05 62 views
4

我有一个不规则索引的时间序列数据与秒的分辨率,如:计算时间在某些状态的时间序列数据

import pandas as pd 
idx = ['2012-01-01 12:43:35', '2012-03-12 15:46:43', 
     '2012-09-26 18:35:11', '2012-11-11 2:34:59'] 
status = [1, 0, 1, 0] 
df = pd.DataFrame(status, index=idx, columns = ['status']) 
df = df.reindex(pd.to_datetime(df.index)) 

In [62]: df 
Out[62]: 
        status 
2012-01-01 12:43:35  1 
2012-03-12 15:46:43  0 
2012-09-26 18:35:11  1 
2012-11-11 02:34:59  0 

,我感兴趣的是今年的分数时的状态为1。办法我目前做的是,我在这一年重新索引df与每一个第二和使用正填充,如:

full_idx = pd.date_range(start = '1/1/2012', end = '12/31/2012', freq='s') 
df1 = df.reindex(full_idx, method='ffill') 

它返回一个DataFrame包含每秒的一年,我可以再计算出均值,以看到的百分比时间在1状态,如:

In [66]: df1 
Out[66]: 
<class 'pandas.core.frame.DataFrame'> 
DatetimeIndex: 31536001 entries, 2012-01-01 00:00:00 to 2012-12-31 00:00:00 
Freq: S 
Data columns: 
status 31490186 non-null values 
dtypes: float64(1) 


In [67]: df1.status.mean() 
Out[67]: 0.31953371123308066 

的问题是,我必须为大量的数据做到这一点,并重新索引它每一秒钟在今年迄今为止最昂贵的操作。

有什么更好的方法来做到这一点?

回答

3

虽然有一种方便的方法将时间序列索引转换为datetime.datetime对象数组,但它似乎没有计算不规则时间序列条目之间时间差的方法。 datetime.timedelta通过减法对象。

In [6]: start_end = pd.DataFrame({'status': [0, 0]}, 
           index=[pd.datetools.parse('1/1/2012'), 
             pd.datetools.parse('12/31/2012')]) 

In [7]: df = df.append(start_end).sort() 

In [8]: df 
Out[8]: 
        status 
2012-01-01 00:00:00  0 
2012-01-01 12:43:35  1 
2012-03-12 15:46:43  0 
2012-09-26 18:35:11  1 
2012-11-11 02:34:59  0 
2012-12-31 00:00:00  0 

In [9]: pydatetime = pd.Series(df.index.to_pydatetime(), index=df.index) 

In [11]: df['duration'] = pydatetime.diff().shift(-1).\ 
       map(datetime.timedelta.total_seconds, na_action='ignore') 

In [16]: df 
Out[16]: 
        status duration 
2012-01-01 00:00:00  0  45815 
2012-01-01 12:43:35  1 6145388 
2012-03-12 15:46:43  0 17117308 
2012-09-26 18:35:11  1 3916788 
2012-11-11 02:34:59  0 4310701 
2012-12-31 00:00:00  0  NaN 

In [17]: (df.status * df.duration).sum()/df.duration.sum() 
Out[17]: 0.31906950786402843 

注:

  • 我们的回答似乎有所不同,因为我第一时间标记零之前设置status,而那些条目NA在df1,因为没有开始值转发填充和NA值被熊猫均值()排除。
  • timedelta.total_seconds()是Python 2.7中的新增功能。
  • 该方法的时序比较与重新索引:

    In [8]: timeit delta_method(df) 
    1000 loops, best of 3: 1.3 ms per loop 
    
    In [9]: timeit redindexing(df) 
    1 loops, best of 3: 2.78 s per loop 
    
+0

这是计算缺少的一天:这是使用日从1/1/2012开始到2012年12月31日的*开始*之间的时间的一小部分, – mstringer

1

另一个潜在的方法是使用traces

import traces 
from dateutil.parser import parse as date_parse 

idx = ['2012-01-01 12:43:35', '2012-03-12 15:46:43', 
     '2012-09-26 18:35:11', '2012-11-11 2:34:59'] 
status = [1, 0, 1, 0] 

# create a TimeSeries from date strings and status 
ts = traces.TimeSeries(default=0) 
for date_string, status_value in zip(idx, status): 
    ts[date_parse(date_string)] = status_value 

# compute distribution 
ts.distribution(
    start=date_parse('2012-01-01'), 
    end=date_parse('2013-01-01'), 
) 
# {0: 0.6818022667476219, 1: 0.31819773325237805} 

值2012年1月1的开始和端之间计算2012年12月31日,而不重新取样(等同2013年1月1日开始),并假定状态在是0今年开始(default=0参数)

时序结果:

In [2]: timeit ts.distribution(
    start=date_parse('2012-01-01'), 
    end=date_parse('2013-01-01') 
) 
619 µs ± 7.25 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)