简体   繁体   English

执行数学sigma和的最快,最有效和pythonic方法是什么?

[英]What's the fastest, most efficient, and pythonic way to perform a mathematical sigma sum?

Let's say that I want to perform a mathematical summation, say the Madhava–Leibniz formula for π , in Python: 假设我想在Python中执行数学求和,比如说πMadhava-Leibniz公式

由latex.codecogs.com/gif.latex?%5Cfrac%7B%5Cpi%7D%7B4%7D%5Capprox%20%5Csum_%7Bk%3D0%7D%5E%7Bn%7D%20%5Cfrac%7B%28生成-1%29%5Ek%7D%7B2k + 1%7D

Within a function called Leibniz_pi(), I could create a loop to calculate the n th partial sum, such as: 在一个名为Leibniz_pi()的函数中,我可以创建一个循环来计算第n 部分和,例如:

def Leibniz_pi(n):
    nth_partial_sum = 0       #initialize the variable
    for i in range(n+1):
        nth_partial_sum += ((-1)**i)/(2*i + 1)
    return nth_partial_sum

I'm assuming it would be faster to use something like xrange() instead of range(). 我假设使用像xrange()而不是range()这样的东西会更快。 Would it be even faster to use numpy and its built in numpy.sum() method? 使用numpy及其内置的numpy.sum()方法会更快吗? What would such an example look like? 这样的例子会是什么样的?

I guess most people will define the fastest solution by @zero using only numpy as the most pythonic, but it is certainly not the fastest. 我想大多数人都会定义@zero最快的解决方案,只使用numpy作为最pythonic,但它肯定不是最快的。 With some additional optimizations you can beat the already fast numpy implementation by a factor of 50. 通过一些额外的优化,您可以将已经快速的numpy实现击败50倍。

Using only Numpy (@zero) 仅使用Numpy(@zero)

import numpy as np
import numexpr as ne
import numba as nb

def Leibniz_point(n):
    val = (-1)**n / (2*n + 1)
    return val

%timeit Leibniz_point(np.arange(1000)).sum()
33.8 µs ± 203 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Make use of numexpr 利用numexpr

n=np.arange(1000)
%timeit ne.evaluate("sum((-1)**n / (2*n + 1))")
21 µs ± 354 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Compile your function using Numba 使用Numba编译您的功能

# with error_model="numpy", turns off division-by-zero checks 
@nb.njit(error_model="numpy",cache=True)
def Leibniz_pi(n):
  nth_partial_sum = 0.       #initialize the variable as float64
  for i in range(n+1):
      nth_partial_sum += ((-1)**i)/(2*i + 1)
  return nth_partial_sum

%timeit Leibniz_pi(999)
6.48 µs ± 38.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Edit, optimizing away the costly (-1)**n 编辑,优化昂贵的(-1)** n

import numba as nb
import numpy as np

#replacement for the much more costly (-1)**n
@nb.njit()
def sgn(i):
    if i%2>0:
        return -1.
    else:
        return 1.

# with error_model="numpy", turns off the division-by-zero checks
#
# fastmath=True makes SIMD-vectorization in this case possible
# floating point math is in general not commutative
# e.g. calculating four times sgn(i)/(2*i + 1) at once and then the sum 
# is not exactly the same as doing this sequentially, therefore you have to
# explicitly allow the compiler to make the optimizations

@nb.njit(fastmath=True,error_model="numpy",cache=True)
def Leibniz_pi(n):
    nth_partial_sum = 0.       #initialize the variable
    for i in range(n+1):
        nth_partial_sum += sgn(i)/(2*i + 1)
    return nth_partial_sum

%timeit Leibniz_pi(999)
777 ns ± 5.36 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

3 suggestions (with speed computation): 3条建议(带速度计算):

define the Leibniz point not the cumulative sum: 定义莱布尼兹而不是累积总和:

def Leibniz_point(n):
    val = (-1)**n / (2*n + 1)
    return val

1) sum a list comprehension 1)总结列表理解

%timeit sum([Leibniz_point(n) for n in range(100)])
58.8 µs ± 825 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit sum([Leibniz_point(n) for n in range(1000)])
667 µs ± 3.41 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

2) standard for loop 2)循环标准

%%timeit
sum = 0
for n in range(100):
    sum += Leibniz_point(n)
61.8 µs ± 4.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%%timeit
sum = 0
for n in range(1000):
    sum += Leibniz_point(n)
    729 µs ± 43.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

3) use a numpy array (suggested) 3)使用numpy数组(建议)

%timeit Leibniz_point(np.arange(100)).sum()
11.5 µs ± 866 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit Leibniz_point(np.arange(1000)).sum()
61.8 µs ± 3.69 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In general, for operations involving collections of more than a few elements, numpy will be faster. 通常,对于涉及多个元素集合的操作, numpy会更快。 A simple numpy implementation could be something like this: 一个简单的numpy实现可能是这样的:

def leibniz(n):
    a = np.arange(n + 1)
    return (((-1.0) ** a) / (2 * a + 1)).sum()

Note that you must specify that the numerator is a float with 1.0 on Python 2. On Python 3, 1 will be fine. 请注意,您必须在Python 2上指定分子是一个带有1.0float 。在Python 3上, 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 假设我在Python中有一个列表。 按部分将其随机化的最有效的Python方法是什么? - Suppose I had a list in Python. What's the most pythonic and efficient way to randomize it by sections? Python:执行此循环的pythonic方法是什么? - Python: what's the pythonic way to perform this loop? 确定字节序的最Pythonic方法是什么? - What's the most Pythonic way of determining endianness? 构建此词典的最pythonic方法是什么? - What's the most pythonic way to build this dictionary? 忽略带有括号的列表中的单词的最有效(pythonic)方法是什么? - What is the most efficient (pythonic) way to ignore words in a list that has parantheses? 重新编写大熊猫列的最有效和pythonic方法是什么? - What is the most efficient & pythonic way to recode a pandas column? 在组合上增加迭代的pythonic或最有效的方法是什么? - What is the pythonic or most efficient way to increase an iteration over combinations? 在 pandas 中计算 limsup/liminf 的最有效和 Pythonic 方法是什么? - What is the most efficient and Pythonic way of calculating limsup/liminf in pandas? 深度复制 class 实例并执行额外操作的最有效和最 Pythonic 的方法 - Most efficient and most Pythonic way to deep copy class instance and perform additional manipulation 在 Python 中迭代列表并找到合适的字符串模式的最快(最有效)方法是什么? - What's the fastest (most efficient) way to iterate through a list and find a fitting string pattern in Python?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM