根据熊猫的日期和事件状态整理数据



我有一个数据集,我想从中了解每天有多少供应商在线。数据帧看起来像这样-

provider_id        event_time   final_status  rank
325  0037dfffff8b03bbdf366a263735e84b 2017-09-04 08:00:19       online     1
326  0037dfffff8b03bbdf366a263735e84b 2017-09-04 08:29:39       online     2
327  0037dfffff8b03bbdf366a263735e84b 2017-09-04 08:44:36      offline     3
328  0037dfffff8b03bbdf366a263735e84b 2017-09-04 09:06:12       online     4
330  0037dfffff8b03bbdf366a263735e84b 2017-09-04 12:23:24       online     5
331  0037dfffff8b03bbdf366a263735e84b 2017-09-04 12:23:47      offline     6
332  0037dfffff8b03bbdf366a263735e84b 2017-09-04 12:45:46       online     7
333  0037dfffff8b03bbdf366a263735e84b 2017-09-04 12:45:56      offline     8
334  0037dfffff8b03bbdf366a263735e84b 2017-09-04 17:38:31       online     9
335  0037dfffff8b03bbdf366a263735e84b 2017-09-04 17:40:51       online    10

样本输出将是这样的。在这里,如果我们查看前3行,我们可以看到提供者从2017-09-04 08:00:192017-09-04 08:44:36是在线的。然后他离线直到CCD_ 3,然后继续在线直到2017-09-04 12:23:24。这就是其余seconds_online值的计算方式。

provider_id         day        start_hour  end_hour  seconds_online  
0   0037dfffff8b03bbdf366a263735e84b  2017-09-04           8         9      2657
1   0037dfffff8b03bbdf366a263735e84b  2017-09-04           9        10      3228 
2   0037dfffff8b03bbdf366a263735e84b  2017-09-04          10        11      3600
3   0037dfffff8b03bbdf366a263735e84b  2017-09-04          11        12      3600
4   0037dfffff8b03bbdf366a263735e84b  2017-09-04          12        13      2746
5   0037dfffff8b03bbdf366a263735e84b  2017-09-04          13        14      10
6   0037dfffff8b03bbdf366a263735e84b  2017-09-04          14        15      0
7   0037dfffff8b03bbdf366a263735e84b  2017-09-04          15        16      0
8   0037dfffff8b03bbdf366a263735e84b  2017-09-04          16        17      0
9   0037dfffff8b03bbdf366a263735e84b  2017-09-04          17        18      140
10  0037dfffff8b03bbdf366a263735e84b  2017-09-04          18        19      0

有了for loop,这很容易,但数据集目前有2000多万行。使用for并不是一个优化的解决方案。它正在显示,大约需要7天的时间。有人能帮忙吗??

您可以试试这段代码,df是pandas数据帧。

df = df.sort(['Date', 'event status'], ascending=[True, False])

有趣的问题。以下是一些想法,没有完整的解决方案,但其中的一些可能是有用的。

如果没有循环,我就无法做到这一点,这真是太遗憾了。因此,我的策略是减少循环的数量。为此,我做了一些预处理。

第一步是消除不必要的";在线行":

import numpy as np
import pandas as pd
df['start'] = ((df.final_status.eq('online'))
& (df.final_status.shift(1).isin(['offline', np.NaN])))
df['end'] = (((df.final_status.eq('offline'))
& (df.final_status.shift(1).eq('online')))
| (df.final_status.shift(-1).isna()))
df = df[df.start != df.end].drop(columns=['final_status', 'start'])

结果(我不显示不相关的列(:

event_time    end
0 2017-09-04 08:00:19  False
2 2017-09-04 08:44:36   True
3 2017-09-04 09:06:12  False
5 2017-09-04 12:23:47   True
6 2017-09-04 12:45:46  False
7 2017-09-04 12:45:56   True
8 2017-09-04 17:38:31  False
9 2017-09-04 17:40:51   True

根据结果,我正在形成区间:

df = pd.concat([df.event_time[df.end.eq(value)].reset_index(drop=True)
for value in (False, True)],
ignore_index=True,
axis='columns').rename(columns={0: 'start', 1: 'end'})

结果:

start                 end
0 2017-09-04 08:00:19 2017-09-04 08:44:36
1 2017-09-04 09:06:12 2017-09-04 12:23:47
2 2017-09-04 12:45:46 2017-09-04 12:45:56
3 2017-09-04 17:38:31 2017-09-04 17:40:51

作为循环的第二步,现在在更少的行上:

idx = pd.date_range(df.start.min().floor('H'), df.end.max().floor('H'), freq='H')
df_secs = pd.DataFrame({'secs': 0}, index=idx)
df_secs.index.name = 'hours'
for s, e in zip(df.start, df.end):
if s.hour == e.hour:
df_secs.loc[s.floor('H'), 'secs'] += (e - s).seconds
else:
df_secs.loc[s.floor('H'), 'secs'] += (s.ceil('H') - s).seconds
hrs = pd.date_range(s.ceil('H'), e.floor('H'), freq='H', closed='left')
df_secs.loc[hrs, 'secs'] += 3600
df_secs.loc[e.floor('H'), 'secs'] += (e - e.floor('H')).seconds

结果(print(df_secs)(:

secs
hours                    
2017-09-04 08:00:00  2657
2017-09-04 09:00:00  3228
2017-09-04 10:00:00  3600
2017-09-04 11:00:00  3600
2017-09-04 12:00:00  1437
2017-09-04 13:00:00     0
2017-09-04 14:00:00     0
2017-09-04 15:00:00     0
2017-09-04 16:00:00     0
2017-09-04 17:00:00   140

我不明白为什么start_hour == 122746start_hour == 1310?我看不出这与您提供的示例数据是如何兼容的。例如,在12:45:56,状态为offline,下一个online状态为17:38:31,所以start_hour == 13不应该有秒吗?

正如我所说,这不是一个完整的解决方案:我想你有很多provider_id,这将需要一个外部groupby环路,等等

最新更新