python - 有没有比 for 循环更快的方法来更改熊猫组
问题描述
我正在使用下面的数据框:
这些是我试图按游戏分组的国际象棋游戏,然后根据该游戏中的移动数对每场游戏执行一个功能......
game_id move_number colour avg_centi
0 03gDhPWr 1 white NaN
1 03gDhPWr 2 black 37.0
2 03gDhPWr 3 white 61.0
3 03gDhPWr 4 black -5.0
4 03gDhPWr 5 white 26.0
5 03gDhPWr 6 black 31.0
6 03gDhPWr 7 white -2.0
... ... ... ... ...
110091 zzaiRa7s 34 black NaN
110092 zzaiRa7s 35 white NaN
110093 zzaiRa7s 36 black NaN
110094 zzaiRa7s 37 white NaN
110095 zzaiRa7s 38 black NaN
110096 zzaiRa7s 39 white NaN
110097 zzaiRa7s 40 black NaN
具体来说,我正在使用pd.cut
创建一个新列,game_phase
列出给定的移动是否在开局、中局、残局中进行。
game_id move_number colour avg_centi phase
0 03gDhPWr 1 white NaN opening
1 03gDhPWr 2 black 37.0 opening
2 03gDhPWr 3 white 61.0 opening
3 03gDhPWr 4 black -5.0 opening
4 03gDhPWr 5 white 26.0 opening
5 03gDhPWr 6 black 31.0 opening
6 03gDhPWr 7 white -2.0 opening
.. ... ... ... ... ...
54 03gDhPWr 55 white 58.0 endgame
55 03gDhPWr 56 black 26.0 endgame
56 03gDhPWr 57 white 116.0 endgame
57 03gDhPWr 58 black 2000.0 endgame
58 03gDhPWr 59 white 0.0 endgame
59 03gDhPWr 60 black 0.0 endgame
60 03gDhPWr 61 white NaN endgame
我正在使用以下代码来实现这一点。请注意,每个游戏必须根据该游戏中的移动总数划分为opening
、middlegame
和箱。endgame
for game_id, group in df.groupby('game_id'):
bins = (0, round(group['move_number'].max() * 1/3), round(group['move_number'].max() * 2/3),
group['move_number'].max())
phases = ["opening", "middlegame", "endgame"]
try:
group.loc[:, 'phase'] = pd.cut(group['move_number'], bins, labels=phases)
except:
group.loc[:, 'phase'] = None
print(group)
问题在于,从数千个游戏中迭代每一个游戏需要很长时间才能找到这一点。
我认为必须有更快的方法来计算它,而不是使用for
循环来遍历组并逐个执行计算。
解决方案
这是我使用一个简单示例提出的方法。
总结一下,3个步骤:
- 您可以
max move number
使用 groupby 找到每个游戏的 - 将新df合并到旧df,包括
max move number
- 通过计算一次为所有游戏添加阶段
move number/max move number
我的方法在,test1()
而你的方法在test2()
:
import pandas
import random
import time
a = []
for group in range(25):
for count in range(random.randint(900, 1000)):
a.append({'group': chr(65 + group), 'count': count})
def test1(x):
b = pandas.DataFrame(x)
max_df = b.groupby(by='group', as_index=False)['count'].max().rename(columns={'count': 'max'})
b = pandas.merge(b, max_df, on='group', how='left')
b['phase'] = 'opening'
b.loc[b['count'] > b['max'] / 3.0, 'phase'] = 'middlegame'
b.loc[b['count'] > b['max'] / 1.5, 'phase'] = 'endgame'
b.drop('max', axis=1, inplace=True)
return b
def test2(x):
df = pandas.DataFrame(x)
df['phase'] = ''
for game_id, group in df.groupby('group'):
bins = (0, round(group['count'].max() * 1 / 3), round(group['count'].max() * 2 / 3),
group['count'].max())
phases = ["opening", "middlegame", "endgame"]
try:
group.loc[:, 'phase'] = pandas.cut(group['count'], bins, labels=phases)
except:
group.loc[:, 'phase'] = None
return df
start_time = time.time()
out1 = test1(a)
print(time.time() - start_time)
start_time = time.time()
out2 = test2(a)
print(time.time() - start_time)
assert out1.to_dict() == out2.to_dict()
这test1
比 快得多test2
,尽管这只是 1 次运行:
test1: 0.09799647331237793
test2: 0.769993782043457
并且test2()
似乎有一些问题:它实际上并没有修改数据框,所以该phase
列是空的。不确定它是否适合你。
推荐阅读
- r - 在 R 数据框中将 fctr 转换为 dbl
- vue-chartjs - Vue-chartjs 使我的响应式图表对我的窗口来说太高了
- java - 为什么我必须为这个迷宫使用 do-while 循环?
- python - 当有更多任务时,许多分布式 dask 工作人员在一次评估后闲置,或者从未收到任何工作
- c - 如何在 Windows 中为 Python 3.7 编译 C 扩展
- ubuntu-18.04 - 如何解决“erpnext”权限拒绝错误?
- asp.net-core - WebSocket 未处于 OPEN 状态
- wordpress - WordPress:3秒后重定向到页面
- oracle - 如何在程序中在 AS 之后放置 2 个条件
- php - 如何在使用正则表达式提交之前检查文本框的输入日期以进行格式设置?