【问题标题】:Nested summation in pythonpython中的嵌套求和
【发布时间】:2021-03-04 13:10:49
【问题描述】:

我正在尝试在 python 中执行以下嵌套求和:

所以我尝试了以下代码:

import numpy as np
gamma = 17
R = 0.5
H = np.array([0.1,0.2])
alpha = np.array([0.1,0.2])
n = 2

F = 0
for i in range(n):
    for j in range(i+1):
        F = F + 3*gamma*H[i]*(R+H[j]*np.tan(alpha[j]))**2

但是,当然,这并没有给我正确的答案,因为它在 j 循环中再次对所有项求和。我的问题是我该如何解决?请记住,这只是一个包含j 的多个求和的大表达式的一小部分,就像上面对i 的求和一样,所以它必须进行一些优化。提前谢谢!

【问题讨论】:

  • 我已经大量更新了我的答案。如果你关心效率,我建议你看看the updated version :)
  • 非常感谢@jonathan.scholbach,我期待在完整的方程式中采用您的解决方案:)

标签: python numpy for-loop math sum


【解决方案1】:

for 循环在这种情况下与 非常相似,即公式中 之外的所有内容都应在for 循环之外,即:

...
F = 0
for i in range(n):
    inner_sum = 0
    for j in range(i+1):
        inner_sum += H[j] * np.tan(alpha[j])
    F += 3 * gamma * H[i] * (R + inner_sum) ** 2

【讨论】:

  • 好的,我认为还有另一种选择,因为我在原始表达式中有大量的内部和,但没关系。感谢您的帮助!
【解决方案2】:

我至少看到以下选项(按提高效率排序):

只是可读的 Pythonic 方式

python 的一个优点是您可以编写这些表达式,非常类似于用数学编写的方式。在您的情况下,您希望 sum 超过 iterable 的数字:

f = sum(
    3 * gamma * H[i] * (
        R + (
            sum(
                H[j] * np.tan(alpha[j])
                for j in range(i+1)
            )
       )
    )**2
    for i in range(n)
)

缓存内部总和

在你的情况下,内部总和

sum(
    H[j] * np.tan(alpha[j])
    for j in range(i+1)
)

被计算多次,而它只是在每次迭代中递增。让我们将这个术语称为inner_sum(index)。那么inner_sum(index-1)已经在之前的迭代中计算过了。因此,当我们在每次迭代中重新计算它时,我们会浪费时间。一种方法是使inner_sum 成为一个函数并缓存其先前的结果。为此,我们可以使用functools.cache

from functools import cache


@cache
def inner_sum(index: int) -> float:
   if not index:
      return H[0] * np.tan(alpha[0])
   return inner_sum(H, index - 1) + H[index] * np.tan(alpha[index])

现在,我们可以写:

f = sum(
    3 * gamma * H[i] * (
        R + inner_sum(i)
    )**2
    for i in range(n)
)

使用生成器生成部分和

这仍然不是内存效率的,因为我们将所有 H[i] for i inner_sum_previous 中。或者你可以让inner_sum 一个正确的generator 一个接一个地吐出(实际上是:yielding)部分总和:

from typing import Generator


def partial_sum() -> Generator[float, None, None]:
    partsum = 0
    index = 0
    while True:
        try:
            partsum += H[index] * np.tan(alpha[index])
            yield partsum
            index += 1
        except IndexError:
            raise StopIteration

有了这个,我们就可以写了;

partial_sum_generator = partial_sum()
f = sum(
    3 * gamma * H[i] * (
        R + next(partial_sum_generator)
    )**2
    for i in range(n)
)

【讨论】:

    【解决方案3】:

    首先在j循环中计算括号内的部分,将其存储在一个变量中,然后将其乘以表达式的其余部分。

    【讨论】:

      【解决方案4】:

      只是为了紧凑和可读性,我会选择这样的东西:

      for i in range(n):
           3*gamma*H[i]*(R + np.sum([H[j]*np.tan(alpha[i]) for j in range(i)]))**2
      

      显然,您也可以将第一个 for 循环转换为列表上的求和,就像我对第二个求和所做的那样,以使表达式更紧凑,但我认为这种方式更具可读性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-09
        相关资源
        最近更新 更多