熊猫:自上次获胜以来每个事件的事件数

时间:2018-09-12 16:17:22

标签: pandas performance for-loop pandas-groupby

这是我的有关在线游戏的数据集的示例。我们拥有用于确认下注的会话ID,下注发生的日期以及下注的结果(赢-输-输):

e = {'session': ['1', '3', '1', '1', '3', '1', '2', '2', '1', '3',  '3', '3', '3', '3',  '2', '3', '3'],
    'date': ['2018-01-01 00:17:05', '2018-01-01 00:30:35', '2018-01-01 00:19:05', '2018-01-03 00:55:22',
             '2018-01-01 00:21:07', '2018-01-01 00:22:09', '2018-02-01 00:35:22', 
             '2018-01-01 00:22:17',  '2018-01-01 00:25:11', '2018-01-01 00:27:28', '2018-01-01 00:29:29',
              '2018-01-01 00:25:09',   '2018-01-01 00:17:01', '2018-02-01 00:31:16',  
             '2018-02-01 00:38:20', '2018-02-01 00:55:15',  '2018-02-01 00:38:16'], 
    'status': ['win', 'loss', 'loss', 'draw', 'loss', 'win', 'loss', 'loss', 'win', 'draw', 'loss', 'loss', 'loss', 
               'win', 'draw', 'loss', 'loss']}

#create dataframe
df2 = pd.DataFrame(data=e)
#sort it by session and date
df2 = df2.sort_values(['session', 'date']).reset_index(drop=True)
df.head()

 session      date           status
0   1   2018-01-01 00:17:05   win
1   1   2018-01-01 00:19:05   loss
2   1   2018-01-01 00:22:09   win
3   1   2018-01-01 00:25:11   win
4   1   2018-01-03 00:55:22   draw

我的目标是为每个环节计算没有赢得比赛的最大次数。这是我根据this SO post的建议所做的:

1。首先,我创建了一个列,其中win = 1 ,其他值= 0

m = {'win':1, 'loss':0, 'draw':0}
df2['status_num'] = df2.status.map(m)

session      date            status   status_num
0   1   2018-01-01 00:17:05  win        1
1   1   2018-01-01 00:19:05  loss       0
2   1   2018-01-01 00:22:09  win        1
3   1   2018-01-01 00:25:11  win        1
4   1   2018-01-03 00:55:22  draw       0

2。对于每个会话,我都会计算自上次获胜以来的天数,然后将结果附加到新的数据框中:

#create list of sessions
plist = list(df2.session.unique())

final = pd.DataFrame()
for i in plist:
    #slice the dataset by session
    sess = df2.loc[df2['session'] == i]
    #calculate the last win occurrence
    sess['Last_win']= sess.groupby(sess.status_num.cumsum()).cumcount()
    #append the result
    final = final.append(sess)

final
session date                status status_num   Last_win
0   1   2018-01-01 00:17:05  win        1         0
1   1   2018-01-01 00:19:05  loss       0         1
2   1   2018-01-01 00:22:09  win        1         0
3   1   2018-01-01 00:25:11  win        1         0
4   1   2018-01-03 00:55:22  draw       0         1

3。最后,我分组以得到最大的序列,每个会话没有任何获胜事件

last_win = final.groupby('session')['Last_win'].max().reset_index()
last_win
session Last_win
0   1     1
1   2     2
2   3     5

代码可以满足我的需要,但是它的性能不是很好,并且由于我拥有大量数据集,因此我想在运行时间方面找到更好的解决方案。 我非常确定瓶颈是for循环,而且对于每次迭代我都会进行groupby的事实,但实际上我想不出另一种方法。 我也尝试了建议使用here的方法,但是我对几天不感兴趣。

1 个答案:

答案 0 :(得分:0)

首先,我将定义一个函数来像这样计算一个会话的差异,注意:这假设您已经按照自己的方式对数据框进行了排序。

def events_to_last_win(df):

    vec = []
    counter=0
    for i in df.index:

        if df.loc[i,'status'] == 'win':
            counter = 0
        else: 
            counter += 1


        vec.append(counter)
    return vec

然后进行初始设置:

import pandas as pd
e = {'session': ['1', '3', '1', '1', '3', '1', '2', '2', '1', '3',  '3', '3', '3', '3',  '2', '3', '3'],
    'date': ['2018-01-01 00:17:05', '2018-01-01 00:30:35', '2018-01-01 00:19:05', '2018-01-03 00:55:22',
             '2018-01-01 00:21:07', '2018-01-01 00:22:09', '2018-02-01 00:35:22', 
             '2018-01-01 00:22:17',  '2018-01-01 00:25:11', '2018-01-01 00:27:28', '2018-01-01 00:29:29',
              '2018-01-01 00:25:09',   '2018-01-01 00:17:01', '2018-02-01 00:31:16',  
             '2018-02-01 00:38:20', '2018-02-01 00:55:15',  '2018-02-01 00:38:16'], 
    'status': ['win', 'loss', 'loss', 'draw', 'loss', 'win', 'loss', 'loss', 'win', 'draw', 'loss', 'loss', 'loss', 
               'win', 'draw', 'loss', 'loss']}


df = pd.DataFrame(data=e)
#sort it by session and date
df = df.sort_values(['session', 'date']).reset_index(drop=True)

然后,我们可以为Last_win列分配一个虚拟值,并使用我们定义的函数通过会话ID更新它:

df['Last_win'] = 0
for session in df.session.unique()):
    df.loc[df.session == session,'Last_win'] = events_to_last_win( df[df.session == session])

df.groupby('session')['Last_win'].max().reset_index()

此方法在我的计算机上运行1000多次的平均运行时间为0.0153894310000004

与问题中发布的方法的1000次运行的平均值相比: 0.19408468899999962

请注意,我尚未检查使用此方法的值,但这应该概述解决问题的更快方法