Python 在数据帧中,根据特定条件更快地计算滚动发生次数
我有这样一个熊猫数据框:Python 在数据帧中,根据特定条件更快地计算滚动发生次数,python,pandas,performance,dataframe,Python,Pandas,Performance,Dataframe,我有这样一个熊猫数据框: name number A 0.8466 A 0.8463 A 0.8482 A 0.8455 A 0.8423 A 0.8405 A 0.842 A 0.8453 A 0.8419 A 0.8394 A 0.8376 A 0.8368 A 0.8388 A 0.8392 A 0.8409 A 0.8415 A 0.8424 A 0.8425 A 0.8433 A 0.8412 A 0.
name number
A 0.8466
A 0.8463
A 0.8482
A 0.8455
A 0.8423
A 0.8405
A 0.842
A 0.8453
A 0.8419
A 0.8394
A 0.8376
A 0.8368
A 0.8388
A 0.8392
A 0.8409
A 0.8415
A 0.8424
A 0.8425
A 0.8433
A 0.8412
A 0.8397
我想计算在3个number
值的滑动窗口中满足上限
和下限
条件的次数。我有一个工作代码:
df['Upper'] = 0
df['Lower'] = 0
for i in range(len(df)):
if i < 1:
df['Upper'].iloc[i] = 0
df['Lower'].iloc[i] = 0
else:
chip_sum_r = 0
chip_sum_s = 0
for j in range(3):
if df['name'].iloc[i-j] == df['name'].iloc[i]:
if df['number'].iloc[i-j] <= df['number'].iloc[i]*1.003 and df['number'].iloc[i-j] > df['number'].iloc[i]:
chip_sum_r += 1
if df['number'].iloc[i-j] >= df['number'].iloc[i]*0.997 and df['number'].iloc[i-j] < df['number'].iloc[i]:
chip_sum_s += 1
df['Upper'].iloc[i] = chip_sum_r
df['Lower'].iloc[i] = chip_sum_s
但是,对于大量数据点来说,这是非常缓慢的。有没有办法加快速度,我不确定矢量化方法在这里是否有效?您可以通过对大小为3的滚动窗口应用自定义函数来实现矢量化 即使你的函数没有矢量化,如果你使用Numba引擎(需要安装一个包),你可能会看到比原始python有显著的性能提升
编辑:如果该应用程序与正常pd或np应用程序类似,则它可能没有矢量化。相反,可以使用.shift()生成一组中间列,并以这种方式构建计算-然后将每个中间计算矢量化。当然我们可以通过
numpy
广播来完成
n=3
s=df.number.values
s=s[:,None]/s
df['Lower']=np.sum(np.tril(np.triu(np.tril((s<=1.003) & (s>1)), -n+1)), 1)
df['Upper']=np.sum(np.tril(np.triu(np.tril((s<1) & (s>=0.997)), -n+1)), 1)
df
Out[52]:
name number Lower Upper
0 A 0.8466 0 0
1 A 0.8463 0 1
2 A 0.8482 2 0
3 A 0.8455 0 1
4 A 0.8423 0 0
5 A 0.8405 0 1
6 A 0.8420 1 1
7 A 0.8453 0 0
8 A 0.8419 0 1
9 A 0.8394 0 1
10 A 0.8376 0 1
11 A 0.8368 0 1
12 A 0.8388 2 0
13 A 0.8392 2 0
14 A 0.8409 2 0
15 A 0.8415 2 0
16 A 0.8424 2 0
17 A 0.8425 2 0
18 A 0.8433 2 0
19 A 0.8412 0 2
20 A 0.8397 0 1
n=3
s=df.number.values
s=s[:,无]/s
df['Lower']=np.sum(np.tril(np.triu(np.tril((s1)),-n+1)),1)
df['Upper']=np.sum(np.tril(np.triu)(np.tril((s=0.997)),-n+1)),1)
df
出[52]:
姓名号码上下
0 A 0.8466 0 0
1 A 0.8463 0 1
2 A 0.8482 2 0
3 A 0.8455 0 1
4 A 0.8423 0 0
5 A 0.8405 0 1
6 A 0.8420 1 1
7 A 0.8453 0 0
8 A 0.8419 0 1
9 A 0.8394 0 1
10 A 0.8376 0 1
11 A 0.8368 0 1
12 A 0.8388 2 0
13 A 0.8392 2 0
14 A 0.8409 2 0
15 A 0.8415 2 0
16 A 0.8424 2 0
17 A 0.8425 2 0
18 A 0.8433 2 0
19 A 0.8412 0 2
20 A 0.8397 0 1
尽管我不确定在测试(10毫秒)后,这是否会大大提高性能,但您可以使用.shift()
作为循环行和np.where()
的替代方法,以满足您的条件。在下面的解决方案中,您总共只需要循环3次,但我测试了Yorben的循环,每次循环0.3毫秒,速度快了30倍
df['Upper'] = 0
df['Lower'] = 0
for j in range(3):
df['Upper'] = np.where((df['name'] == df.shift(j)['name'])
& (df.shift(j)['number'] <= df['number']*1.003)
& (df.shift(j)['number'] > df['number']),
df['Upper'] + 1, df['Upper'])
df['Lower'] = np.where((df['name'] == df.shift(j)['name'])
& (df.shift(j)['number'] >= df['number']*0.997)
& (df.shift(j)['number'] < df['number']),
df['Lower'] + 1, df['Lower'])
此解决方案比我的解决方案快30倍左右。不过我真的不太明白+1的性能。哇,这是超快速的,如此快速的编码,令人印象深刻。然而,这并不是我所需要的——检查结果df。此外,没有检查滚动范围内的
名称
是否与@YOBEN_S相同
df['Upper'] = 0
df['Lower'] = 0
for j in range(3):
df['Upper'] = np.where((df['name'] == df.shift(j)['name'])
& (df.shift(j)['number'] <= df['number']*1.003)
& (df.shift(j)['number'] > df['number']),
df['Upper'] + 1, df['Upper'])
df['Lower'] = np.where((df['name'] == df.shift(j)['name'])
& (df.shift(j)['number'] >= df['number']*0.997)
& (df.shift(j)['number'] < df['number']),
df['Lower'] + 1, df['Lower'])
name number Upper Lower
0 A 0.8466 0 0
1 A 0.8463 1 0
2 A 0.8482 0 2
3 A 0.8455 1 0
4 A 0.8423 0 0
5 A 0.8405 1 0
6 A 0.8420 1 1
7 A 0.8453 0 0
8 A 0.8419 1 0
9 A 0.8394 1 0
10 A 0.8376 1 0
11 A 0.8368 1 0
12 A 0.8388 0 2
13 A 0.8392 0 2
14 A 0.8409 0 2
15 A 0.8415 0 2
16 A 0.8424 0 2
17 A 0.8425 0 2
18 A 0.8433 0 2
19 A 0.8412 2 0
20 A 0.8397 1 0