在pandas中对可变长度前瞻循环进行矢量化
这是我的数据的一个非常简化的版本:在pandas中对可变长度前瞻循环进行矢量化,pandas,Pandas,这是我的数据的一个非常简化的版本: +----+---------+---------------------+ ||用户id |启动后的秒数|| +----+---------+---------------------+ | 0 | 1 | 10 | | 1 | 1 | 12 | | 2 | 1 | 15 | | 3 | 1 |
+----+---------+---------------------+
||用户id |启动后的秒数||
+----+---------+---------------------+
| 0 | 1 | 10 |
| 1 | 1 | 12 |
| 2 | 1 | 15 |
| 3 | 1 | 52 |
| 4 | 1 | 60 |
| 5 | 1 | 67 |
| 6 | 1 | 120 |
| 7 | 2 | 55 |
| 8 | 2 | 62 |
| 9 | 2 | 105 |
| 10 | 3 | 200 |
| 11 | 3 | 206 |
+----+---------+---------------------+
这是我想提供的数据:
+----+---------+---------------------+-----------------+------------------+
||用户id |启动后的秒数|会话|顺序|会话|持续时间|
+----+---------+---------------------+-----------------+------------------+
| 0 | 1 | 10 | 1 | 5 |
| 1 | 1 | 12 | 1 | 5 |
| 2 | 1 | 15 | 1 | 5 |
| 3 | 1 | 52 | 2 | 15 |
| 4 | 1 | 60 | 2 | 15 |
| 5 | 1 | 67 | 2 | 15 |
| 6 | 1 | 120 | 3 | 0 |
| 7 | 2 | 55 | 1 | 7 |
| 8 | 2 | 62 | 1 | 7 |
| 9 | 2 | 105 | 2 | 0 |
| 10 | 3 | 200 | 1 | 6 |
| 11 | 3 | 206 | 1 | 6 |
+----+---------+---------------------+-----------------+------------------+
我对会话的概念是一组来自单个用户的事件,间隔不超过10秒,会话的持续时间定义为会话中第一个事件和最后一个事件之间的差异(以秒为单位)
我已经编写了能够实现我想要的功能的Python
将熊猫作为pd导入
事件数据=[[1,10]、[1,12]、[1,15]、[1,52]、[1,60]、[1,67]、[1,120],
[2, 55], [2, 62], [2, 105],
[3, 200], [3, 206]]
events=pd.DataFrame(data=events\u data,columns=['user\u id','seconds\u-since\u-start']))
def记录会话(索引范围、顺序、持续时间):
对于索引_范围内的i:
事件。在[i,‘session_序数’]=序数
事件。在[i,‘会话持续时间’]=持续时间
会话索引=[]
当前用户=上一次会话时间=会话开始时间=-1
会话数量=0
对于i,在events.iterrows()中的行:
如果行['user_id']!=当前用户或(行['seconds\u自\u开始]]-上一次\u时间)>10:
记录会话(会话索引、会话编号、上一次会话时间-会话开始)
会话索引=[i]
会话数+=1
会话\u开始=行['seconds\u session\u start']
如果行['user_id']!=当前用户:
当前用户=行['user\u id']
会话数=1
上一次\u时间=行['自\u开始后的秒数']
session_index.append(i)
记录会话(会话索引、会话编号、上一次会话时间-会话开始)
我的问题是这需要多长时间来运行。正如我所说,这是我的数据的一个非常简化的版本,我的实际数据有7000000行。有没有一种方法可以矢量化(从而加速)这样的算法,根据可变长度的look aheads生成额外的列?您可以尝试:
# Create a helper boolean Series
s = df.groupby('user_id')['seconds_since_start'].diff().gt(10)
df['session_ordinal'] = s.groupby(df['user_id']).cumsum().add(1).astype(int)
df['session_duration'] = (df.groupby(['user_id', 'session_ordinal'])['seconds_since_start']
.transform(lambda x: x.max() - x.min()))
[输出]
user\u id seconds\u自启动会话起的秒数\u顺序会话\u持续时间
0 1 10 1 5
1 1 12 1 5
2 1 15 1 5
3 1 52 2 15
4 1 60 2 15
5 1 67 2 15
6 1 120 3 0
7 2 55 1 7
8 2 62 1 7
9 2 105 2 0
10 3 200 1 6
11 3 206 1 6
的答案很好。它包含一些我不熟悉的技术或调用。这个答案复制了他的答案,并添加了丰富的注释
我们首先构建一个辅助布尔级数。本系列记录为任何用户启动附加会话的事件。这可以作为布尔级数,因为在数值上下文中,它们的行为类似于整数0和1(引用自)。让我们一点一点地把这个系列放在一起
starts\u session=events.groupby('user\u id')['seconds\u since\u start'].diff().gt(10)
首先,我们根据用户id()对事件进行分组,然后选择'seconds\u since\u start'列并调用diff()。events.groupby('user\u id')['seconds\u since\u start'].diff()的结果是
+----+----------------------+
||启动后的秒数|
+----+----------------------+
|0 |南|
| 1 | 2.0 |
| 2 | 3.0 |
| 3 | 37.0 |
| 4 | 8.0 |
| 5 | 7.0 |
| 6 | 53.0 |
|7 |南|
| 8 | 7.0 |
| 9 | 43.0 |
|10 |南|
| 11 | 6.0 |
+----+----------------------+
我可以看到,每个小组的开始都已经获得了正确的NaN差异,因为之前没有这样的事件