我有一个运动员比赛数据的巨大数据帧,看起来如下:
Race_ID Athlete_ID Distance Rank
1 1 100 3
2 1 400 6
3 1 1500 1
4 1 100 6
5 1 100 1
6 1 1500 1
7 2 100 1
8 2 400 2
9 2 400 1
10 2 1500 6
11 2 1500 4
12 2 100 1
13 2 100 1
我想制作一个名为Dist_Preference
的新专栏,通过计算运动员赢得该距离的条件概率来了解运动员更擅长什么距离(100(短(、400(中(、1500(长((。例如:
p(赢得100米比赛的运动员1 |这是100米比赛(=2/3
p(运动员1赢得400米比赛|这是400米比赛(=0/1=0
p(运动员1赢得1500米比赛|这是1500米比赛(=2/2=1
因此,运动员1显然具有长跑的偏好。第四个,所需的列看起来像
Race_ID Athlete_ID Distance Rank Dist_Preference
1 1 100 3 1500
2 1 400 6 1500
3 1 1500 1 1500
4 1 100 6 1500
5 1 100 1 1500
6 1 1500 1 1500
7 2 100 1 100
8 2 400 2 100
9 2 400 1 100
10 2 1500 6 100
11 2 1500 4 100
12 2 100 1 100
13 2 100 1 100
我已经编写了一个子程序,通过定义一个方法来实现这一点,该方法如上所述计算条件概率,然后使用.apply
,但对于大型数据帧来说,速度非常慢,我想知道是否有任何快速的方法可以做到这一点。
非常感谢。
创建一个布尔列:win
以识别获胜的比赛,然后使用aggfuncmean
透视数据帧,后者将计算概率,然后使用idxmax
根据获胜概率找到首选距离
df['win'] = df['Rank'] == 1
prob = df.pivot_table('win', 'Athlete_ID', 'Distance')
df['preferred_dist'] = df['Athlete_ID'].map(prob.idxmax(1))
结果
Race_ID Athlete_ID Distance Rank win preferred_dist
0 1 1 100 3 False 1500
1 2 1 400 6 False 1500
2 3 1 1500 1 True 1500
3 4 1 100 6 False 1500
4 5 1 100 1 True 1500
5 6 1 1500 1 True 1500
6 7 2 100 1 True 100
7 8 2 400 2 False 100
8 9 2 400 1 True 100
9 10 2 1500 6 False 100
10 11 2 1500 4 False 100
11 12 2 100 1 True 100
12 13 2 100 1 True 100
try:
df
Race_ID Athlete_ID Distance Rank
1 1 100 3
2 1 400 6
3 1 1500 1
4 1 100 6
5 1 100 1
6 1 1500 1
7 2 100 1
8 2 400 2
9 2 400 1
10 2 1500 6
11 2 1500 4
12 2 100 1
13 2 100 1
df1 = df.groupby(['Athlete_ID', 'Distance']).agg(nbr_of_races=('Rank', lambda x: len(x)),
nbr_of_races_won=('Rank', lambda x: len([i for i in x if i == 1]))).reset_index()
df1['performance'] = (df1['nbr_of_races_won']*100/df1['nbr_of_races']).round(2)
df1
Athlete_ID Distance nbr_of_races nbr_of_races_won performance
0 1 100 3 1 33.33
1 1 400 1 0 0.00
2 1 1500 2 2 100.00
3 2 100 3 3 100.00
4 2 400 2 1 50.00
5 2 1500 2 0 0.00
#sort by performance
df1 = df1.sort_values(['Athlete_ID', 'performance'], ascending=[True, False])
Athlete_ID Distance nbr_of_races nbr_of_races_won performance
2 1 1500 2 2 100.00
0 1 100 3 1 33.33
1 1 400 1 0 0.00
3 2 100 3 3 100.00
4 2 400 2 1 50.00
5 2 1500 2 0 0.00
#keep only the best performed Distance for each Athlete
df1 = df1.drop_duplicates('Athlete_ID')
Athlete_ID Distance nbr_of_races nbr_of_races_won performance
2 1 1500 2 2 100.0
3 2 100 3 3 100.0
#merge
df = df.merge(df1.loc[:, ['Athlete_ID', 'Distance']].rename(columns={"Distance": "preferred_dist"}), on='Athlete_ID', how='left')
df
Race_ID Athlete_ID Distance Rank preferred_dist
0 1 1 100 3 1500
1 2 1 400 6 1500
2 3 1 1500 1 1500
3 4 1 100 6 1500
4 5 1 100 1 1500
5 6 1 1500 1 1500
6 7 2 100 1 100
7 8 2 400 2 100
8 9 2 400 1 100
9 10 2 1500 6 100
10 11 2 1500 4 100
11 12 2 100 1 100
12 13 2 100 1 100