将活动数据分为几个小时,并获取每小时的持续时间

西格德

我的活动数据如下:

login_time          logout_time         a           b           c 
2018-03-01 08:15:20 2018-03-01 08:16:01 0.000000    0.000000    62
2018-03-01 08:16:28 2018-03-01 08:19:38 52.199083   21.000718   62
2018-03-01 08:57:10 2018-03-01 09:46:26 52.199083   21.000590   62
2018-03-01 10:05:43 2018-03-01 10:08:51 0.000000    0.000000    62
2018-03-02 09:45:40 2018-03-02 09:47:16 52.239281   21.010551   62

我需要计算按日期和小时划分的会话持续时间(以秒为单位),因此结果应与此类似:

a           b           c       duration hour   date
0.000000    0.000000    62.0    41.0    8.0     2018-03-01
52.199083   21.000718   62.0    190.0   8.0     2018-03-01
52.199083   21.000590   62.0    170.0   8.0     2018-03-01
52.199083   21.000590   62.0    2786.0  9.0     2018-03-01
0.000000    0.000000    62.0    188.0   10.0    2018-03-01
52.239281   21.010551   62.0    96.0    9.0     2018-03-02 

如您所见,源df中的第三行被划分为结果df中的两行。有时logout_time可能是login_time之后的第二天,这是另一个问题。

我使用下面的代码完成了该工作,但是它在行中进行迭代时非常慢。我处理的文件超过100万行,因此欢迎提供任何提示以提高效率。

def SplitAvail(df):
    new_split=pd.DataFrame()
    for i in np.arange(df.shape[0]):
        row=df.iloc[i,:]
        if (row.login_time.day==row.logout_time.day):
                new_split=new_split.append(MakeSplitAvail(row))
        else: 
            row1=row.copy()
            row1.logout_time=datetime(row.login_time.year,row.login_time.month,
                           row.login_time.day, 23,59,59)
            new_split=new_split.append(MakeSplitAvail(row1))
            row2=row.copy()
            row2.login_time=datetime(row.logout_time.year,row.logout_time.month,
                           row.logout_time.day, 0,0,0)
            new_split=new_split.append(MakeSplitAvail(row2))
    return new_split

def MakeSplitAvail(row):
    split=pd.DataFrame()
    for j in np.arange(row.login_time.hour, row.logout_time.hour+1,1):
        row_t=row.copy()
        h1=datetime(row.login_time.year,row.login_time.month,
                           row.login_time.day, j,0,0)
        h2=h1+ dt.timedelta(hours=1)
        row_t['hour']=j
        row_t['duration']=(min(row_t.logout_time, h2)-max(row_t.login_time, h1))\
            .total_seconds()
        split=split.append(row_t)
    return split
古斯塔沃·贝塞拉

答案概述:

  1. 制作样本数据集
  2. 添加带有持续时间,小时和日期信息的列
  3. 处理需要拆分的行
  4. 合并拆分行和非拆分行以生成最终结果

1.制作样本数据集

我将开始日期设置为与原始数据相同,并使用随机数生成器生成其他数据。在Macbook上,这大约需要40毫秒

start = pd.Timestamp('2018-03-01 08:15:20').value
login_time = start + np.random.randint(10, 1000, size=100000).cumsum() * 10 ** 9
logout_time = login_time + np.random.lognormal(mean=6, size=100000) * 10 ** 9
df = pd.DataFrame({'login_time': pd.to_datetime(login_time), 
                   'logout_time': pd.to_datetime(logout_time).round(freq='s')})

数据集有10万条记录。大约82%的用户不需要拆分,大约17%的用户需要1个拆分,> 1%的用户需要2个以上的拆分。可以通过更改使用的参数/分布类型来更改

df['hour_diff'].value_counts()

0     82309
1     17117
2       467
3        76
4        16
5         8
6         3
8         2
16        1
10        1
Name: hour_diff, dtype: int64

2.添加带有持续时间,小时,日期信息的列

这是相对简单的。无需进行纯Python迭代。%当日期更改时,模运算符用于修复负时差。在Macbook上,这大约需要1.4 s

df['duration'] = (df['logout_time'] - df['login_time']).apply(lambda x: x.total_seconds())
df['date'] = df['login_time'].apply(lambda x: x.date())
df['hour'] = df['login_time'].apply(lambda x: x.hour)
df['hour_diff'] = (df['logout_time'].apply(lambda x: x.hour) - df['hour']) % 24

3.处理需要拆分的行

这是困难的部分。在这里,我使用itertuples了相对快速的数据帧迭代。我将所有记录元组放在一个列表中,并从该列表中构建一个新的数据框。在新手中这是一个非常常见的错误,但是Pandas在迭代数据框架构建方面非常糟糕,因此我建议您避免这种情况。创建记录列表,然后从中建立新的数据框,速度更快。process_record被实现为生成器功能,使事情变得更加优雅/高效。在Macbook上,这大约需要1.5 s

def process_record(t):
    cumtime = 0
    r = t._asdict()
    for i in range(t.hour_diff + 1):
        pseudo_logout = min(t.logout_time, pd.Timestamp(t.date) + pd.Timedelta(hours=t.hour + i + 1))
        duration = (pseudo_logout - t.login_time).total_seconds() - cumtime
        cumtime += duration
        r['duration'] = duration
        yield tuple(r.values())

records = []
for t in df[df['hour_diff'] > 0].itertuples():
    for r in process_record(t):
        records.append(r)
split_df = pd.DataFrame(records)
split_df = split_df.drop(0, axis=1)
split_df.columns = df.columns

4.将拆分行与非拆分行合并

最后,只需将split_df与中未更改的记录连接起来df在我的Macbook上,这大约需要30毫秒

merged_df = pd.concat([split_df, df[df['hour_diff'] == 0]])
merged_df = merged_df.sort_values(by='login_time').reset_index(drop=True)

最终结果如下所示:

                login_time         logout_time  duration        date  hour  hour_diff
0      2018-03-01 08:21:29 2018-03-01 08:30:12     523.0  2018-03-01     8          0
1      2018-03-01 08:28:17 2018-03-01 08:42:47     870.0  2018-03-01     8          0
2      2018-03-01 08:33:17 2018-03-01 08:35:29     132.0  2018-03-01     8          0
3      2018-03-01 08:40:13 2018-03-01 08:45:50     337.0  2018-03-01     8          0
4      2018-03-01 08:45:12 2018-03-01 08:49:54     282.0  2018-03-01     8          0
5      2018-03-01 08:54:28 2018-03-01 09:01:19     332.0  2018-03-01     8          1
6      2018-03-01 08:54:28 2018-03-01 09:01:19      79.0  2018-03-01     8          1
7      2018-03-01 09:01:30 2018-03-01 09:03:06      96.0  2018-03-01     9          0
8      2018-03-01 09:04:01 2018-03-01 09:05:44     103.0  2018-03-01     9          0
9      2018-03-01 09:17:30 2018-03-01 09:46:40    1750.0  2018-03-01     9          0
10     2018-03-01 09:21:40 2018-03-01 09:22:31      51.0  2018-03-01     9          0

总的来说,单个内核上的100k记录(30 us /记录)大约需要3s。结果可能会有所不同,具体取决于需要拆分的记录数量,但是我想您应该能够轻松地每分钟处理1m +条记录。

我还做了这个可以作为一个Jupyter笔记本电脑在这里

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在 Oracle SQL 中将持续时间拆分为每小时间隔?

将开始时间和总持续时间转换为每小时经过的时间

R日期范围数据帧到每小时持续时间的总和

熊猫-将事件持续时间的每小时转换为单独的一行

连续几个小时内的MYSQL SUM持续时间

根据日期时间列将 1 行拆分为多行每小时数据

如何每小时获取数据

持续时间超过24小时

将每小时时间序列数据帧转换为单个小时的多个数据帧

如何将日期时间序列转换为以小时为单位的实际持续时间?

在谷歌表格中获取持续时间类型单元格的小时数

获取两个Date对象之间的持续时间(以小时和分钟为单位)-JavaScript

如何在 jupyter notebook 中使用 python 3 仅将持续时间转换为小时而不是天和小时?

每小时在R中获取在线数据

TSQL:获取每小时的销售数据

从每小时获取每日数据

将持续时间(秒)转换为小时和分钟,并跳过空值

Oracle,将持续时间行除以一小时

如何在php中将时间拆分为每小时

系统服务持续时间不超过6小时

IF 函数来计算持续时间(小时:分钟:秒)

Powershell格式的持续时间,以小时和分钟为单位

将数据表拆分为R中的每小时总计

如何计算从选定时间(小时)到给定持续时间的时间(以小时为单位)

将时间序列数据分成一行时间间隔(PythonicWay)-每小时

将轮班数据(开始和结束时间)分解为每小时数据

如何将每小时数据转换为6/12/24每小时数据

以 1 小时、5 分钟或 1 小时 5 分钟的形式显示持续时间

Highcharts:以小时为单位的 yAxis 持续时间每 24 小时重置一次