我有一个熊猫数据帧df
,并希望在函数中执行以下计算。到目前为止最长的那条生产线是一条cumprod。我想知道是否有加速的方法?就像在numpy中一样,它们是获得相同结果的不同方法,例如np.inner
vs np.einsum
,我想知道是否可以在这里做类似的事情。
import pandas as pd
In [122]: import numpy as np
In [123]: df = pd.DataFrame(np.random.randn(100000, 1000))
In [124]: %time ((1+df).cumprod(axis=0)-1)
CPU times: user 5.22 s, sys: 884 ms, total: 6.1 s
Wall time: 6.12 s
答案 0 :(得分:1)
您可以使用NumPy而不是Pandas进行计算。 对于您的输入大小,这大约为5%,虽然不令人兴奋,但总比没有好。对于较小的输入,收益要大得多。
import pandas as pd
import numpy as np
arr = np.random.randn(100000, 1000)
df = pd.DataFrame(arr)
x = ((1 + df).cumprod(axis=0) - 1)
y = np.cumprod(1 + arr, axis=0) - 1
print(np.allclose(x, y))
鉴于这是相同的结果,时间是:
arr = np.random.randn(100000, 1000)
df = pd.DataFrame(arr)
%timeit ((1 + df).cumprod(axis=0) - 1)
# 3.64 s ± 76.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.cumprod(1 + arr, axis=0) - 1
# 3.42 s ± 19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
显示输入的上述速度增益。
对于较小的输入,相差较大,例如:
arr = np.random.randn(1000, 10)
df = pd.DataFrame(arr)
%timeit ((1 + df).cumprod(axis=0) - 1)
# 469 µs ± 4.13 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit np.cumprod(1 + arr, axis=0) - 1
# 36.6 µs ± 427 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
表明在这种情况下,在NumPy中执行计算的速度比在熊猫中快13倍。
如@hpaulj所建议的,np.multiply.accumulate()
可以变得更快一些。
# for shape = (100000, 1000)
%timeit np.multiply.accumulate(1 + arr, axis=0) - 1
# 3.38 s ± 79.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
,对于较小的输入:
# for shape = (1000, 10)
%timeit np.multiply.accumulate(1 + arr, axis=0) - 1
# 35.8 µs ± 423 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
但是,像往常一样,这类微基准测试应带有一粒盐,尤其是在观察到如此小的差异时。
答案 1 :(得分:1)
如果您愿意使用其他模块来加快计算速度,我建议您使用import java.text.DecimalFormat;
import java.util.Scanner;
public class Calculate {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("#.#####");
Scanner scanner = new Scanner(System.in);
double n = scanner.nextDouble();
double x = scanner.nextDouble();
double factorial = 1;
double pow = 1;
double S = 0;
double result;
for (int i = 1; i <= n; i++) {
factorial *= i;
pow *= x;
result = (factorial / pow);
S += result;
}
double finalResult = (S + 1);
String formatted = df.format(finalResult);
System.out.println(formatted);
}
}
。 Numba将python代码编译为LLVM,并且专门旨在使用numba
加速数值计算。
由于numpy
尚不支持将numba
之类的kwargs
与axis=0
一起使用,因此您的代码将如下所示:
np.cumprod
一些时间表明,numba大约比在DataFrame上使用cumprod快4倍,比使用numpy快3.7倍:
import numpy as np
import pandas as pd
import numba as nb
@nb.njit(parallel=True)
def nb_cumprod(arr):
y = np.empty_like(arr)
for i in range(arr.shape[1]):
y[:, i] = np.cumprod(1 + arr[:, i]) - 1
return y
arr = np.random.randn(100000, 1000)
df = pd.DataFrame(arr)
x = ((1 + df).cumprod(axis=0) - 1)
y = np.cumprod(1 + arr, axis=0) - 1
z = nb_cumprod(arr)
print(np.allclose(x, z))
您可以使用诸如%timeit ((1 + df).cumprod(axis=0) - 1)
# 6.83 s ± 482 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.cumprod(1 + arr, axis=0) - 1
# 6.38 s ± 509 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit nb_cumprod(arr)
# 1.71 s ± 158 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
之类的其他选项来进一步提高性能,但这会产生略微的不同结果。