这是我的有关在线游戏的数据集的示例。我们拥有用于确认下注的会话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的方法,但是我对几天不感兴趣。
答案 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
请注意,我尚未检查使用此方法的值,但这应该概述解决问题的更快方法