我怎样才能用 Numpy 加快速度?
How can I speed this up with Numpy?
所以我已经为此苦苦挣扎了 2 天,终于设法让它工作了,但我想知道是否有办法加快速度,因为我有大量数据要处理。
这里的目标是我的数据帧的每一行每一列,我想计算一个增量和(elt(n-1)+ elt(n)),然后取绝对值并比较局部绝对值到前一个,以便在我专栏的最后一个元素处获得最大值。我虽然简单地使用滚动总和或简单的列总和会起作用,但不知何故我做不到。这些最大值是在 2000 行上滚动计算的。 (所以对于 elt n,我从第 n 行直到第 n+2000 行,等等)。最后,我将得到一个长度为原始数据帧减去 2000 个元素的数据帧。
关于速度,完成所有 4 列大约需要 1 分钟(这是针对仅包含大约 5000 个元素的相对较小的文件,其中大部分会大 4 倍)。
理想情况下,我想大幅加快“for pulse in range(2000):”循环中的内容,但如果我能加快整个代码也很好。
我不确定我该如何使用列表理解。我检查了 numpy accumulate() 函数或 rolling() 但它没有给我想要的东西。
edit1:缩进。
edit2:这里是第一列的前 10 行输入和输出的示例(以减少这里的繁忙)。问题是您至少需要 2000 行输入才能获得结果中的第一项,因此不确定它在这里是否真的有用。
Input :
-2.1477511E-12
2.0970403E-12
2.0731764E-12
1.7241669E-12
1.2260080E-12
7.3381503E-13
8.2330457E-13
-9.2472616E-13
-1.1275693E-12
-1.3184806E-12
Output:
2.25436311E-10
2.28640040E-10
2.27405083E-10
2.25331907E-10
2.23607740E-10
2.22381732E-10
2.21647917E-10
2.20824612E-10
2.21749338E-10
2.22876908E-10
这是我的代码:
ys_integral_check_reduced = ys_integral_check[['A', 'B', 'C', 'D']]
for col in ys_integral_check_reduced.columns:
pulse=0
i=0
while (ys_integral_check_reduced.loc[i+1999,col] != 0 and i<len(ys_integral_check_reduced)-2000):
cur = 0
max = 0
for pulse in range(2000):
cur = cur + ys_integral_check_reduced.loc[i+pulse, col]
if abs(cur) > max:
max = abs(cur)
pulse = pulse+1
ys_integral_check_reduced_final.loc[i, col] = max
i = i+1
print(ys_integral_check_reduced_final)
如果我没理解错的话,我创建了一个玩具示例(WINDOW
大小为 3)。
import pandas as pd
WINDOW = 3
ys_integral_check = pd.DataFrame({'A':[1, 2, -5, -6, 1, -10, -1, -10, 7, 4, 5, 6],
'B':[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]})
ys_integral_check['C'] = -ys_integral_check['B']
看起来像这样:
A B C
0 1 1 -1
1 2 2 -2
2 -5 3 -3
3 -6 4 -4
4 1 5 -5
5 -10 6 -6
6 -1 7 -7
7 -10 8 -8
8 7 9 -9
9 4 10 -10
10 5 11 -11
11 6 12 -12
您的解决方案给出:
ys_integral_check_reduced_final = pd.DataFrame(columns=['A', 'B', 'C'])
ys_integral_check_reduced = ys_integral_check[['A', 'B', 'C']]
for col in ys_integral_check_reduced.columns:
pulse=0
i=0
while (ys_integral_check_reduced.loc[i+WINDOW-1,col] != 0 and i<len(ys_integral_check_reduced)-WINDOW):
cur = 0
max = 0
for pulse in range(WINDOW):
cur = cur + ys_integral_check_reduced.loc[i+pulse, col]
if abs(cur) > max:
max = abs(cur)
pulse = pulse+1
ys_integral_check_reduced_final.loc[i, col] = max
i = i+1
print(ys_integral_check_reduced_final)
A B C
0 3 6 6
1 9 9 9
2 11 12 12
3 15 15 15
4 10 18 18
5 21 21 21
6 11 24 24
7 10 27 27
8 16 30 30
这是使用 Pandas 和 Rolling.apply()
的变体:
ys_integral_check_reduced_final = ys_integral_check[['A', 'B', 'C']].rolling(WINDOW).apply(lambda w: w.cumsum().abs().max()).dropna().reset_index(drop=True)
给出:
A B C
0 3.0 6.0 6.0
1 9.0 9.0 9.0
2 11.0 12.0 12.0
3 15.0 15.0 15.0
4 10.0 18.0 18.0
5 21.0 21.0 21.0
6 11.0 24.0 24.0
7 10.0 27.0 27.0
8 16.0 30.0 30.0
9 15.0 33.0 33.0
有一个额外的行,因为我相信你的解决方案在最后跳过了一个可能的 window。
我在具有 100'000 行和 3 列且 window 大小为 2000 的随机 DataFrame 上对其进行了测试,处理时间为 18 秒:
import time
import numpy as np
WINDOW = 2000
DF_SIZE = 100000
test_df = pd.DataFrame(np.random.random((DF_SIZE, 3)), columns=list('ABC'))
t0 = time.time()
test_df.rolling(WINDOW).apply(lambda w: w.cumsum().abs().max()).dropna().reset_index(drop=True)
t1 = time.time()
print(t1-t0) # 18.102170944213867
所以我已经为此苦苦挣扎了 2 天,终于设法让它工作了,但我想知道是否有办法加快速度,因为我有大量数据要处理。
这里的目标是我的数据帧的每一行每一列,我想计算一个增量和(elt(n-1)+ elt(n)),然后取绝对值并比较局部绝对值到前一个,以便在我专栏的最后一个元素处获得最大值。我虽然简单地使用滚动总和或简单的列总和会起作用,但不知何故我做不到。这些最大值是在 2000 行上滚动计算的。 (所以对于 elt n,我从第 n 行直到第 n+2000 行,等等)。最后,我将得到一个长度为原始数据帧减去 2000 个元素的数据帧。
关于速度,完成所有 4 列大约需要 1 分钟(这是针对仅包含大约 5000 个元素的相对较小的文件,其中大部分会大 4 倍)。
理想情况下,我想大幅加快“for pulse in range(2000):”循环中的内容,但如果我能加快整个代码也很好。 我不确定我该如何使用列表理解。我检查了 numpy accumulate() 函数或 rolling() 但它没有给我想要的东西。
edit1:缩进。
edit2:这里是第一列的前 10 行输入和输出的示例(以减少这里的繁忙)。问题是您至少需要 2000 行输入才能获得结果中的第一项,因此不确定它在这里是否真的有用。
Input :
-2.1477511E-12
2.0970403E-12
2.0731764E-12
1.7241669E-12
1.2260080E-12
7.3381503E-13
8.2330457E-13
-9.2472616E-13
-1.1275693E-12
-1.3184806E-12
Output:
2.25436311E-10
2.28640040E-10
2.27405083E-10
2.25331907E-10
2.23607740E-10
2.22381732E-10
2.21647917E-10
2.20824612E-10
2.21749338E-10
2.22876908E-10
这是我的代码:
ys_integral_check_reduced = ys_integral_check[['A', 'B', 'C', 'D']]
for col in ys_integral_check_reduced.columns:
pulse=0
i=0
while (ys_integral_check_reduced.loc[i+1999,col] != 0 and i<len(ys_integral_check_reduced)-2000):
cur = 0
max = 0
for pulse in range(2000):
cur = cur + ys_integral_check_reduced.loc[i+pulse, col]
if abs(cur) > max:
max = abs(cur)
pulse = pulse+1
ys_integral_check_reduced_final.loc[i, col] = max
i = i+1
print(ys_integral_check_reduced_final)
如果我没理解错的话,我创建了一个玩具示例(WINDOW
大小为 3)。
import pandas as pd
WINDOW = 3
ys_integral_check = pd.DataFrame({'A':[1, 2, -5, -6, 1, -10, -1, -10, 7, 4, 5, 6],
'B':[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]})
ys_integral_check['C'] = -ys_integral_check['B']
看起来像这样:
A B C
0 1 1 -1
1 2 2 -2
2 -5 3 -3
3 -6 4 -4
4 1 5 -5
5 -10 6 -6
6 -1 7 -7
7 -10 8 -8
8 7 9 -9
9 4 10 -10
10 5 11 -11
11 6 12 -12
您的解决方案给出:
ys_integral_check_reduced_final = pd.DataFrame(columns=['A', 'B', 'C'])
ys_integral_check_reduced = ys_integral_check[['A', 'B', 'C']]
for col in ys_integral_check_reduced.columns:
pulse=0
i=0
while (ys_integral_check_reduced.loc[i+WINDOW-1,col] != 0 and i<len(ys_integral_check_reduced)-WINDOW):
cur = 0
max = 0
for pulse in range(WINDOW):
cur = cur + ys_integral_check_reduced.loc[i+pulse, col]
if abs(cur) > max:
max = abs(cur)
pulse = pulse+1
ys_integral_check_reduced_final.loc[i, col] = max
i = i+1
print(ys_integral_check_reduced_final)
A B C
0 3 6 6
1 9 9 9
2 11 12 12
3 15 15 15
4 10 18 18
5 21 21 21
6 11 24 24
7 10 27 27
8 16 30 30
这是使用 Pandas 和 Rolling.apply()
的变体:
ys_integral_check_reduced_final = ys_integral_check[['A', 'B', 'C']].rolling(WINDOW).apply(lambda w: w.cumsum().abs().max()).dropna().reset_index(drop=True)
给出:
A B C
0 3.0 6.0 6.0
1 9.0 9.0 9.0
2 11.0 12.0 12.0
3 15.0 15.0 15.0
4 10.0 18.0 18.0
5 21.0 21.0 21.0
6 11.0 24.0 24.0
7 10.0 27.0 27.0
8 16.0 30.0 30.0
9 15.0 33.0 33.0
有一个额外的行,因为我相信你的解决方案在最后跳过了一个可能的 window。
我在具有 100'000 行和 3 列且 window 大小为 2000 的随机 DataFrame 上对其进行了测试,处理时间为 18 秒:
import time
import numpy as np
WINDOW = 2000
DF_SIZE = 100000
test_df = pd.DataFrame(np.random.random((DF_SIZE, 3)), columns=list('ABC'))
t0 = time.time()
test_df.rolling(WINDOW).apply(lambda w: w.cumsum().abs().max()).dropna().reset_index(drop=True)
t1 = time.time()
print(t1-t0) # 18.102170944213867