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包含一年中每一秒的 a,然后我可以计算平均值,以查看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

问题是我必须为大量数据执行此操作,并且一年中的每一秒重新索引它是迄今为止最昂贵的操作。

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

4

2 回答 2

3

似乎没有一种 pandas 方法来计算不规则时间序列的条目之间的时间差,尽管有一种方便的方法可以将时间序列索引转换为对象数组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因为没有前向填充的起始值,并且 Pandas mean() 排除了 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
    
于 2013-01-05T07:10:49.190 回答
1

另一种可能的方法是使用跟踪

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)
于 2017-08-03T05:59:22.600 回答