让我解释一下背景:我有一个数据框,描述了竞赛结果,在每个“日期”中,您可以看到参加比赛的“类型”以及其得分“xx”。
我的代码的作用是计算每个“日期”中“类型”之间得分差异,然后获取所有相互竞争的类型过去比赛结果的差异之和('win_comp_past_difs')。
下面您可以看到数据和模型以及输出结果。
## I. DATA AND MODEL ##
I.1. 数据
import pandas as pd
import numpy as np
idx = [np.array(['Jan-18', 'Jan-18', 'Feb-18', 'Mar-18', 'Mar-18', 'Mar-18','Mar-18', 'Mar-18', 'May-18', 'Jun-18', 'Jun-18', 'Jun-18','Jul-18', 'Aug-18', 'Aug-18', 'Sep-18', 'Sep-18', 'Oct-18','Oct-18', 'Oct-18', 'Nov-18', 'Dec-18', 'Dec-18',]),np.array(['A', 'B', 'B', 'A', 'B', 'C', 'D', 'E', 'B', 'A', 'B', 'C','A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'A', 'B', 'C'])]
data = [{'xx': 1}, {'xx': 5}, {'xx': 3}, {'xx': 2}, {'xx': 7}, {'xx': 3},{'xx': 1}, {'xx': 6}, {'xx': 3}, {'xx': 5}, {'xx': 2}, {'xx': 3},{'xx': 1}, {'xx': 9}, {'xx': 3}, {'xx': 2}, {'xx': 7}, {'xx': 3}, {'xx': 6}, {'xx': 8}, {'xx': 2}, {'xx': 7}, {'xx': 9}]
df = pd.DataFrame(data, index=idx, columns=['xx'])
df.index.names=['date','type']
df=df.reset_index()
df['date'] = pd.to_datetime(df['date'],format = '%b-%y')
df=df.set_index(['date','type'])
df['xx'] = df.xx.astype('float')
它看起来像这样:
xx
date type
2018-01-01 A 1.0
B 5.0
2018-02-01 B 3.0
2018-03-01 A 2.0
B 7.0
C 3.0
D 1.0
E 6.0
2018-05-01 B 3.0
2018-06-01 A 5.0
B 2.0
C 3.0
2018-07-01 A 1.0
2018-08-01 B 9.0
C 3.0
2018-09-01 A 2.0
B 7.0
2018-10-01 C 3.0
A 6.0
B 8.0
2018-11-01 A 2.0
2018-12-01 B 7.0
C 9.0
I.2. 模型(在大型数据框中非常缓慢)
# get differences of pairs, useful for win counts and win_difs
def get_diff(x):
teams = x.index.get_level_values(1)
tmp = pd.DataFrame(x[:,None]-x[None,:],columns = teams.values,index=teams.values).stack()
return tmp[tmp.index.get_level_values(0)!=tmp.index.get_level_values(1)]
new_df = df.groupby('date').xx.apply(get_diff).to_frame()
# group by players
groups = new_df.groupby(level=[1,2])
# sum function
def cumsum_shift(x):
return x.cumsum().shift()
# assign new values
df['win_comp_past_difs'] = groups.xx.apply(cumsum_shift).sum(level=[0,1])
以下是模型输出的示例:
xx win_comp_past_difs
date type
2018-01-01 A 1.0 0.0
B 5.0 0.0
2018-02-01 B 3.0 NaN
2018-03-01 A 2.0 -4.0
B 7.0 4.0
C 3.0 0.0
D 1.0 0.0
E 6.0 0.0
2018-05-01 B 3.0 NaN
2018-06-01 A 5.0 -10.0
B 2.0 13.0
C 3.0 -3.0
2018-07-01 A 1.0 NaN
2018-08-01 B 9.0 3.0
C 3.0 -3.0
2018-09-01 A 2.0 -6.0
B 7.0 6.0
2018-10-01 C 3.0 -10.0
A 6.0 -10.0
B 8.0 20.0
2018-11-01 A 2.0 NaN
2018-12-01 B 7.0 14.0
C 9.0 -14.0
如果您难以理解用户自定义函数(def)的作用,请允许我在下面对其进行解释。
为了说明这一点,我将使用数据框(groupby)中的一个组。
以下是用户自定义函数的工作原理解释。
## II. EXPLANATION OF THE USER-DEFINED FUNCTION ##
因此,为了让您了解用户定义函数的工作原理,让我选择 groupby 中的特定组。
II.1 选择特定的组
gb = df.groupby('date')
gb2 = gb.get_group((list(gb.groups)[2]))
它看起来像这样:
xx
date type
2018-03-01 A 2.0
B 7.0
C 3.0
D 1.0
E 6.0
II.2 创建竞争对手(团队)列表
teams = gb2.index.get_level_values(1)
II.3 创建一个以'type'为基准,计算 'xx'差值的数据框
df_comp= pd.DataFrame(gb2.xx[:,None]-gb2.xx[None,:],columns = teams.values,index=teams.values)
这看起来像这样:
A B C D E
A 0.0 -5.0 -1.0 1.0 -4.0
B 5.0 0.0 4.0 6.0 1.0
C 1.0 -4.0 0.0 2.0 -3.0
D -1.0 -6.0 -2.0 0.0 -5.0
E 4.0 -1.0 3.0 5.0 0.0
从这一点开始,我使用stack()函数作为中间步骤返回到原始数据框。剩下的可以在 I. 数据和模型 中跟进。
如果您能详细说明代码以使其更高效且执行速度更快,我将不胜感激。