Python 计算定义为间隔的用户会话数

Python 计算定义为间隔的用户会话数,python,pandas,intervals,Python,Pandas,Intervals,我有一个用户会话数据集,加载到一个数据框中: SessionID, UserID, Logon_time, Logoff_time Adx1YiRyvOFApQiniyPWYPo,AbO6vW58ta1Bgrqs.RA0uHg,2016-01-05 07:46:56.180,2016-01-05 08:04:36.057 AfjMzw8In8RDqK6jIfItZPs,Ae8qOxLzozJHrC2pr2dOw88,2016-01-04 14:48:47.183,2016-01-04 14:53

我有一个用户会话数据集,加载到一个数据框中:

SessionID, UserID, Logon_time, Logoff_time
Adx1YiRyvOFApQiniyPWYPo,AbO6vW58ta1Bgrqs.RA0uHg,2016-01-05 07:46:56.180,2016-01-05 08:04:36.057
AfjMzw8In8RDqK6jIfItZPs,Ae8qOxLzozJHrC2pr2dOw88,2016-01-04 14:48:47.183,2016-01-04 14:53:30.210
AYIdSJYsRw5PptkFfEOXPa0,AX3Xy8dRDBRAlhyy3YaWw6U,2016-01-04 11:06:37.040,2016-01-04 16:34:38.770
Ac.WXBBSl75KqEuBmNljYPE,Ae8qOxLzozJHrC2pr2dOw88,2016-01-04 10:58:04.227,2016-01-04 11:21:10.520
AekXRDR3mBBDh49IIN2HdU8,Ae8qOxLzozJHrC2pr2dOw88,2016-01-04 10:16:08.040,2016-01-04 10:34:20.523
AVvL3VSWSq5Fr.f4733X.T4,AX3Xy8dRDBRAlhyy3YaWw6U,2016-01-04 09:19:29.773,2016-01-04 09:40:25.157
我想做的是将此数据转换为具有两列的数据帧:

  • 时间戳/周期(例如,分辨率为分钟)
  • 当时存在的会话数
我可以对单个时间戳执行此操作,方法是将datetime范围转换为
间隔
,然后检查给定时间戳位于该间隔的行数


然而,如果我想这样做一年或两年,以分钟或小时的分辨率,我将在一年内完成8760个循环(以小时为例)……这可能不是一个交易破坏者,但我想知道是否有人有任何其他(可能更优雅)的建议或想法。

IIUC,我们可以这样做:

df.apply(lambda x: pd.Series([1] * len(pd.date_range(x.Logon_time, x.Logoff_time, freq='T')), 
         index=pd.date_range(x.Logon_time, x.Logoff_time, freq='T')), axis=1)\
  .stack().reset_index(level=0, drop=True).resample('T').count()
输出(总人数):

使用熊猫可视化检查所有数据:

df.apply(lambda x: pd.Series([1] * len(pd.date_range(x.Logon_time, x.Logoff_time, freq='T')),
                             index=pd.date_range(x.Logon_time, x.Logoff_time, freq='T')), axis=1)\
  .stack().reset_index(level=0, drop=True).resample('T').count().plot()

我最终使用了与Scott的答案稍有不同的解决方案,但他的方法是关键的,因为观察(记录)的数量相对较低,而另一方面,时间元素的数量(例如秒,取决于所需的分辨率)考虑到从第一次观察到最后一次观察之间经过的时间,这个值要大得多

但是,我首先将所有生成的日期范围(系列)收集到一个列表中,并在第二个单独的步骤中将它们连接起来,这可以更快地使用
apply()
连续修改原始数据帧

然后,打印只需要一条额外的语句:

df_sessions_2.plot()

# Expand the datetime range, creating records according to the given resolution (e.g. minutes).
# This creates a Series object for each session. All of those Series objects are then added to a list
# in order to concatenate them in 1 go, which is more efficient.
sessions=[]

for key, cols in df_sessions.iterrows():
    sess = pd.Series(data=pd.date_range(start=cols['logon'].floor('T'),
                                        end=cols['logoff'].ceil('T'),
                                        freq='T'),
                     name='sess_dt')
    sessions.append(sess)

# Concatenate all Series objects and convert to a DataFrame
df_sessions_2 = pd.DataFrame(pd.Series().append(sessions, ignore_index=True), columns=['ref_dt'])

# Add a counter which we can use to aggregate
df_sessions_2['sess_cnt'] = 1

# Aggregate according to the datetime
df_sessions_2 = df_sessions_2.groupby('ref_dt').sum()
df_sessions_2.plot()