如何在Pandas中检测时间序列中的间隙和连续时间段

16

我有一个以日期为索引的pandas数据框。 我想选择所有按时间段连续的间隔和所有按时间段连续的天数。 我该如何做到这一点?

没有列,只有日期索引的数据框示例:

In [29]: import pandas as pd

In [30]: dates = pd.to_datetime(['2016-09-19 10:23:03', '2016-08-03 10:53:39','2016-09-05 11:11:30', '2016-09-05 11:10:46','2016-09-05 10:53:39'])

In [31]: ts = pd.DataFrame(index=dates)

如您所见,有一个2016年8月3日至2016年9月19日的间隔。我该如何检测这些间隔,以便我可以创建描述性统计信息,例如40个间隔,中位数为“x”等等。此外,我可以看到2016年9月5日至2016年9月6日是两天的范围。我如何检测这些范围并打印出描述性统计信息?

理想情况下,每种情况的结果都将作为另一个Dataframe返回,因为我想使用Dataframe中的其他列进行分组。


你能添加一些数据样本吗?请查看“如何创建良好可重复的pandas示例”(https://dev59.com/O2Ij5IYBdhLWcg3wk182) - jezrael
好的,我现在就添加。 - Noah Gift
2个回答

17

Pandas版本1.0.1有一个内置方法DataFrame.diff(),你可以使用它来完成这个任务。一个好处是你可以使用Pandas系列函数,如mean()快速计算gaps系列对象的汇总统计信息。

from datetime import datetime, timedelta
import pandas as pd

# Construct dummy dataframe
dates = pd.to_datetime([
    '2016-08-03',
    '2016-08-04',
    '2016-08-05',
    '2016-08-17',
    '2016-09-05',
    '2016-09-06',
    '2016-09-07',
    '2016-09-19'])
df = pd.DataFrame(dates, columns=['date'])

# Take the diff of the first column (drop 1st row since it's undefined)
deltas = df['date'].diff()[1:]

# Filter diffs (here days > 1, but could be seconds, hours, etc)
gaps = deltas[deltas > timedelta(days=1)]

# Print results
print(f'{len(gaps)} gaps with average gap duration: {gaps.mean()}')
for i, g in gaps.iteritems():
    gap_start = df['date'][i - 1]
    print(f'Start: {datetime.strftime(gap_start, "%Y-%m-%d")} | '
          f'Duration: {str(g.to_pytimedelta())}')

如果我在df中使用“日期”列作为索引,如何估计增量?函数pd.index.difference()执行不同的操作。 - Ilias Machairas

6

以下是一些开始的内容:

df = pd.DataFrame(np.ones(5),columns = ['ones'])
df.index = pd.DatetimeIndex(['2016-09-19 10:23:03', '2016-08-03 10:53:39', '2016-09-05 11:11:30', '2016-09-05 11:10:46', '2016-09-06 10:53:39'])
daily_rng = pd.date_range('2016-08-03 00:00:00', periods=48, freq='D')
daily_rng = daily_rng.append(df.index)
daily_rng = sorted(daily_rng)
df =  df.reindex(daily_rng).fillna(0)
df = df.astype(int)
df['ones'] = df.cumsum()

cumsum()函数在'ones'这个参数上创建了一个分组变量,将你提供的点作为分割点来划分数据。如果你将df打印成电子表格形式,就会很容易理解:

print df.head()

                     ones
2016-08-03 00:00:00     0
2016-08-03 10:53:39     1
2016-08-04 00:00:00     1
2016-08-05 00:00:00     1
2016-08-06 00:00:00     1

print df.tail()
                     ones
2016-09-16 00:00:00     4
2016-09-17 00:00:00     4
2016-09-18 00:00:00     4
2016-09-19 00:00:00     4
2016-09-19 10:23:03     5

现在要完成的任务:

df = df.reset_index()
df = df.groupby(['ones']).aggregate({'ones':{'gaps':'count'},'index':{'first_spotted':'min'}})
df.columns = df.columns.droplevel()

这将会给出:

              first_time  gaps
ones                          
0    2016-08-03 00:00:00     1
1    2016-08-03 10:53:39    34
2    2016-09-05 11:10:46     1
3    2016-09-05 11:11:30     2
4    2016-09-06 10:53:39    14
5    2016-09-19 10:23:03     1

这看起来是一个良好的开端。不过在cumsum之后我有点迷失了。此时:In [11]: df = df.astype(int) In [12]: df.head() Out[12]: ones 2016-08-03 00:00:00 0 2016-08-03 10:53:39 1 2016-08-04 00:00:00 0 2016-08-05 00:00:00 0 2016-08-06 00:00:00 0 - Noah Gift
关键步骤是获取一个分组变量,这就是 cumsum 的作用。 - Dickster
你能解释一下如何使用分组变量来检测第一个间隙和第一个连续的串吗? - Noah Gift
到目前为止,解决方案是否已经正确地显示了间隙?我们可以稍后解决连续的串。 - Dickster
答案正确吗? - Dickster
显示剩余3条评论

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