【问题标题】:Iterate over list of NumPy matrices遍历 NumPy 矩阵列表
【发布时间】:2018-02-16 16:40:24
【问题描述】:

我有一个行矩阵列表:

rows = [ matrix([[1, 0, 0]]), matrix([[0, 1, 0]]), matrix([[0, 0, 1]]) ]

我尝试使用 for (a, b, c) in rows: 循环这些内容,但我得到了一个错误,而不是这个工作:

ValueError:没有足够的值来解包(预期 3,得到 1)

预期的行为是将行中的三个元素解包到a, b, c

for (a, b, c) in rows:
    print(f"{a} {b} {c}")
> 1 0 0
> 0 1 0
> 0 0 1

不幸的是,这适用于[1, 0, 0],但不适用于[[1, 0, 0]]

我意识到这是因为他们是[[doubly packed]],但我想知道这个问题是否有简单的解决方案?

【问题讨论】:

  • 请同时包含“预期行为”(参见minimal reproducible example)。否则很难准确回答你的问题..
  • 您在 numpy 数组/矩阵上使用 for 循环是否有原因?您是否首先创建此列表?
  • @MSeifert 抱歉,我认为这很明显,但我想我应该更清楚地说明,所以我添加了一个示例!
  • @roganjosh 我正在遍历行矩阵中的值;这些都是长度 3,因此将值简单地解压缩到 a, b, c 会很方便。我已经创建了矩阵列表。
  • 感谢您的编辑。现在确实更清楚了。 :)

标签: python numpy for-loop matrix iterable-unpacking


【解决方案1】:

您似乎想解压每个矩阵本身。在这种情况下,我会建议:不要使用 matrix 或 NumPy。也没有理由使用 NumPy 矩阵。甚至NumPy documentation 声明您应该更喜欢数组而不是矩阵。但在这种情况下,您应该使用普通列表,如果您对它们进行迭代或解包,它们会更快。

因此,您首先要遍历每个矩阵,然后解压缩其中的每一个。但你必须分两步完成:

for mat in rows:      # this iterates over the list and gives you each matrix
    # this unpacks the matrix
    # to make it work faster I converted it to a list first using "tolist"
    # note that I needed to index it because it's a 2D matrix!
    a, b, c = mat.tolist()[0]
    print(a, b, c)  

也可以在一行中完成这两个步骤:

for a, b, c in (mat.tolist()[0] for mat in rows):
    print(a, b, c)

【讨论】:

  • 感谢您的关注,但列表是矩阵乘法的结果。不过,您的解决方案速度令人印象深刻,我喜欢单线解决方案,即使它有点不直观。
【解决方案2】:

一个问题是对矩阵的一行进行索引仍然会给出一个矩阵。一种解决方法是将矩阵转换为一维数组:

In [368]: for r in rows:
     ...:     a,b,c=r.A1
     ...:     print(a,b,c)
     ...:     
1 0 0
0 1 0
0 0 1

Numpy matrix to array


In [370]: for r in rows:
     ...:     print(r.shape,r[0].shape)
     ...:     
(1, 3) (1, 3)
(1, 3) (1, 3)
(1, 3) (1, 3)

我通常不使用或不推荐从数组中解包值。这违背了数组的一般性。拆包(除非使用“*”术语)修复尺寸。但通常数组可以有多个维度,并且尺寸很大。

也不鼓励np.matrix。如果这些元素是np.array,那么就不会有这个持久的二维问题。

【讨论】:

    【解决方案3】:

    由于我们使用a,b,c 从每个矩阵的第一行中提取元素,看来我们可以保证每行有 3 个元素,并且每个矩阵每行都有一个元素。因此,一个简单的解决方案(如所要求的)是在使用循环时使用数组构造函数并挤出单例嵌套级别,就像这样 -

    for a,b,c in np.array(rows)[:,0]:
    

    或者更简单的np.squeeze() -

    for a,b,c in np.squeeze(rows):
    

    请注意,这不是最节省内存的方法,但可以作为提取所需标量值的简单方法。

    这是一个示例运行 -

    In [375]: for a,b,c in np.squeeze(rows):
         ...:     print(a,b,c)
         ...:     
    (1, 0, 0)
    (0, 1, 0)
    (0, 0, 1)
    

    【讨论】:

    • 虽然我很欣赏优雅,但这太糟糕了。您将矩阵的 list 转换为 array 只是为了使用 for-loop 对其进行迭代?
    • 还要注意问题使用f-strings 所以答案至少应该有() 用于打印:)
    • @MSeifert 正如我所说,我更喜欢问题中所述的simple solution 部分。同意,这个不是很节省内存:)
    • 在各个方面都效率低下(但很简单——我同意你)。解压数组或对其进行迭代要慢得多。只需计时 3 种方法;我的:20us,hpaulj:35us,你的:67us。
    • np.squeeze 似乎是将原始代码转换为工作解决方案的最简单方法。内存无关紧要,因为列表相对较小,但这确实是一个有效点。但既然没有优化标签,那应该不太重要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2016-02-12
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多