【问题标题】:Iterating over a list of arrays while making changes to each array在对每个数组进行更改时迭代数组列表
【发布时间】:2018-03-01 22:46:43
【问题描述】:

这是我上一个问题的后续帖子:Referring to arrays in a for-loop

我想概括那里提出的解决方案,以便能够完成更复杂的任务,例如将列附加到包含某些计算结果的每个数组:

import numpy as np
list=[one, two, three]

for arr in list:
    arr=np.column_stack([arr,5*arr[:,2]-arr[:,1])])

所有三个数组都具有相同的维度。

【问题讨论】:

    标签: python arrays python-3.x numpy for-loop


    【解决方案1】:
    In [59]: one=np.arange(6).reshape(2,3)
    In [60]: two=np.arange(6).reshape(2,3)
    

    暂时忘记循环,尝试更改one

    In [61]: arr = one
    In [62]: arr=np.column_stack([arr,5*arr[:,2]-arr[:,1]])
    In [63]: arr
    Out[63]: 
    array([[ 0,  1,  2,  9],
           [ 3,  4,  5, 21]])
    In [65]: one
    Out[65]: 
    array([[0, 1, 2],
           [3, 4, 5]])
    

    此操作已更改 arr,但未更改 one。最初 arr 引用了与 one 相同的对象 (ndarray),但在新赋值之后,它引用了一个新数组。

    for arr in alist:
        arr = ....
    

    arr 被分配了一个元素 alist。但是在循环中它被分配了另一个东西,而不改变原始对象。在下一次迭代中,arr 被分配到列表中的下一个元素,依此类推。

    您需要记住几件事。

    • Python 如何为变量赋值
    • Python 如何为迭代变量赋值
    • column_stack 之类的函数

    在你之前的问题中

    In [69]: for arg in [one,two]:
        ...:     arg[:,1:] += 10
        ...:     
    In [70]: one
    Out[70]: 
    array([[ 0, 11, 12],
           [ 3, 14, 15]])
    In [71]: two
    Out[71]: 
    array([[ 0, 11, 12],
           [ 3, 14, 15]])
    

    这是因为arg[:,1:] += 10 正在修改当前分配给arg 的数组。一个数组是mutable;元素值可以就地更改。

    np.column_stack() 不会就地执行。它创建了新数组。

    关于使用列表更改 onetwo 的唯一方法是以下操作序列:

    In [72]: newlist=[np.column_stack([arr,5*arr[:,2]-arr[:,1]]) for arg in [one,two]]
    In [73]: newlist
    Out[73]: 
    [array([[ 0,  1,  2,  9,  9],
            [ 3,  4,  5, 21, 21]]), array([[ 0,  1,  2,  9,  9],
            [ 3,  4,  5, 21, 21]])]
    In [74]: one
    Out[74]: 
    array([[ 0, 11, 12],
           [ 3, 14, 15]])
    In [75]: one, two = newlist
    In [76]: one
    Out[76]: 
    array([[ 0,  1,  2,  9,  9],
           [ 3,  4,  5, 21, 21]])
    

    In[72] 创建一个带有新数组的新列表。 In[75] 将这些新数组分配给变量onetwo。这抹去了他们以前的参考资料。实际上我做了one=[np.column_stack([one,5*one[:,2]-one[:,1]]),同样的two

    【讨论】:

      【解决方案2】:

      分配给变量不会更新列表,它只是对数组中值的临时引用。

      使用enumerate获取列表索引,然后用结果替换即可。

      for index, arr in enumerate(myList):
          myList[index] = np.column_stack([arr,5*arr[:,2]-arr[:,1])])
      

      另外,避免使用内置类和函数的名称作为您自己的变量名。 list 是标准类。

      【讨论】:

      • 谢谢,但不幸的是这不起作用。数组中没有任何内容被替换。
      • 您是否希望它也修改变量onetwothree
      • 是的,想法是把计算结果列附加到三个数组的每一个上。
      • 使用变量只会返回对其包含的值的引用,它不会返回对变量本身的引用。您不能通过从它构建的数组来更改变量的值。但如果变量包含可变数据,您可以改变该对象。
      • 这必须使用对象本身的方法来完成,而不是分配给引用它的变量。
      【解决方案3】:

      恐怕您引用的解决方案只能概括为对数组的就地更改。任何改变大小的东西都会 AFAIK 创建一个新数组。

      所以这个

      >>> X,Y,Z = (np.arange(i+1, i+10, dtype=float).reshape(3, 3) for i in range(3))
      >>> L = [X,Y,Z]
      >>> for arr in L:
      ...    np.sin(arr, out=arr)
      

      或者这个

      >>> for arr in L:
      ...     arr[1] = arr[1, ::-1]
      

      会起作用的。

      你甚至可以替换整个数组,只要你在原地做:

      >>> for arr in L:
      ...     arr[...] = 1.7
      

      但是这个

      >>> for arr in L:
      ...    np.append(arr, arr[-1])
      

      不会更改原始数组而是创建新数组。重新分配给 arr 将无济于事,因为它只是将名称 arr 重新绑定到新对象。

      【讨论】:

        【解决方案4】:

        不要忘记,在 Python 中,变量是对值的引用。迭代变量是一个变量,所以给这个变量赋一个新值不会改变可迭代对象。

        在这种情况下,为什么不使用列表推导式?

        import numpy as np
        my_list = [one, two, three]
        
        my_list = [np.column_stack([arr,5*arr[:,2]-arr[:,1])]) for arr in list]
        

        请不要影响listtype...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-21
          • 1970-01-01
          • 1970-01-01
          • 2019-09-15
          • 2014-03-25
          • 1970-01-01
          相关资源
          最近更新 更多