【问题标题】:How does updating a Python for loop within a list work?更新列表中的 Python for 循环如何工作?
【发布时间】:2019-02-14 14:36:16
【问题描述】:

在 Michael Nielsen 的神经网络教程中,他有以下代码:

def update_mini_batch(self, mini_batch, eta):
    """The ``mini_batch`` is a list of tuples ``(x, y)``, and ``eta``
    is the learning rate."""
    nabla_b = [np.zeros(b.shape) for b in self.biases]
    nabla_w = [np.zeros(w.shape) for w in self.weights]
    for x, y in mini_batch:
        delta_nabla_b, delta_nabla_w = self.backprop(x, y)
        nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
        nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
    self.weights = [w-(eta/len(mini_batch))*nw
                    for w, nw in zip(self.weights, nabla_w)]
    self.biases = [b-(eta/len(mini_batch))*nb
                   for b, nb in zip(self.biases, nabla_b)]

我了解元组和列表是什么,我了解 zip 函数在做什么,但我不了解变量 nb、dnb、nw 和 dnw 如何在这 2 行代码中更新:

        nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
        nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]

谁能帮助解释这两行中发生的魔法?

【问题讨论】:

  • 欢迎来到 StackOverflow!请澄清:a)你的意思是来自neuralnetworksanddeeplearning.com的一章?哪一个? b) npnumpy?
  • 您是否 (a) 不了解 for 如何出现在列表中:[x for y in z],或者 (b) 如何同时分配两个名称:for a, b in x
  • 我想分别澄清nb+dnb for nbdnb in zip(nabla_b, delta_nabla_b)开始。

标签: python python-3.x list list-comprehension


【解决方案1】:

这两行是Pythonlist comprehensions的典型例子。

本质上,对于您的第一个列表:

nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]

这意味着:

  1. zip(nabla_b, delta_nabla_b) 中取出第一对;将它们命名为 nbdnb
  2. 添加它们 (nb+dnb)
  3. 将结果设为新列表nabla_b的第一个元素
  4. 转到第 2 对等的第一步,将结果附加到 nabla_b,直到 zip(nabla_b, delta_nabla_b) 中的所有对都用完

作为一个简单的例子,下面的列表推导:

squares = [x**2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

相当于下面的for循环:

squares = []

for x in range(10):
    squares.append(x**2)

print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

有关更多示例和快速介绍,请参阅 here

【讨论】:

  • 啊,我现在明白了。谢谢你。我的困惑是将nb+dnb for nbdnb in zip(nabla_b, delta_nabla_b) 视为单独的语句,它们会以某种方式将2 个元素的列表返回到nabla_b。这根本不正确。
【解决方案2】:

zip 函数将两个列表逐个元素地粘在一起,所以如果你给它:

a = [1, 2, 3, 4]
b = ["a", "b", "c", "d"]

zip(a, b) 会返回:

[(1, "a"), (2, "b"), ...]

(每个元素都是tuple

您可以使用元素 tuple 中每个变量之间的逗号来解压缩 tuples(或 lists)的 lists 元素:

for elem_a, elem_b in zip(a, b):
    print(elem_a, elem_b)

这将打印:

1 a
2 b
3 c
4 d

因此,在您的情况下,它将两个列表 nabla_bdelta_nabla_b 元素相加,因此您会得到一个列表,其中每个元素都是压缩列表中相应元素的总和。

这可能看起来有点奇怪,因为for 循环都在一行上,但这被称为“列表推导”。简单的列表理解读起来像英语。

【讨论】:

  • 您只是忽略了理解部分,我认为这是OP误解的一部分。 +1 虽然您简化了(可能不是故意的)zip 的行为。在 Python 2 中它只返回一个列表,而在 Python 3 中它返回一个 zip 对象(即生成器)——不过,我发现将它呈现给新手更合理。
  • @Rightleg 我同意 - 我自己选择关注列表理解部分,因为 OP 明确表示“我了解 zip 函数在做什么”...
  • 是的,我总是错过问题的症结所在,并且离题了。我只明确概述了 zip 正在做什么,因为在我看来这是解释解包的必要条件。
猜你喜欢
  • 1970-01-01
  • 2022-06-13
  • 2022-07-07
  • 2020-06-07
  • 2023-03-05
  • 2018-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多