【问题标题】:How to sequentially fill a 3d matrix in python?如何在python中顺序填充3d矩阵?
【发布时间】:2018-11-23 06:28:22
【问题描述】:

我有一个维度为 (n, m, p) 的 nd 数组“A”,并且我有一个长度为 n*m 的列表,其中包含数组 a1、a2、.. 每个数组的长度为 p。我要做的是使用数组'a'顺序(按行)填充'A'。例如,考虑以下示例:

A = np.empty ((2,3,4))

a1 = np.array([1,2,3,0])
a2 = np.array([3,4,6,9])
a3 = np.array([9,5,8,5])
a4 = np.array([1,5,4,2])
a5 = np.array([9,7,0,5])
a6 = np.array([4,3,2,1])
lst = [a1, a2, a3, a4, a5, a6]

我正在寻找一些方法来做

A = DoSomething(A, lst)
print(A)
array([[[ 1.,  2.,  3.,  0.],
        [ 3.,  4.,  6.,  9.],
        [ 9.,  5.,  8.,  5.]],
       [[ 1.,  5.,  4.,  2.],
        [ 9.,  7.,  0.,  5.],
        [ 4.,  3.,  2.,  1.]]])

所以这样A[0, 0, :]=a1, A[0, 1, :]=a2等等。

【问题讨论】:

    标签: python list numpy numpy-ndarray


    【解决方案1】:

    你可以的

    >>> A.reshape(len(lst), -1)[...] = lst
    >>> A
    array([[[1., 2., 3., 0.],
            [3., 4., 6., 9.],
            [9., 5., 8., 5.]],
    
           [[1., 5., 4., 2.],
            [9., 7., 0., 5.],
            [4., 3., 2., 1.]]])
    

    放大示例的几个时间点:

    >>> A = np.empty ((2000,300,40))
    >>> lst = 100000*[l.repeat(10) for l in lst]
    >>> 
    >>> from timeit import timeit
    >>> kwds = dict(globals=globals(), number=5)
    >>> 
    # my solution: fast, short, readable
    >>> timeit("A.reshape(len(lst), -1)[...] = lst", **kwds)
    0.8862412960734218
    # @hpaulj's suggestion slow, very short, very readable
    >>> timeit("A.flat[:] = lst", **kwds)
    1.7412563359830528
    # @FHTMitchell 1 fast, long, index-heavy
    >>> timeit("for index in range(A.shape[0]): A[index] = lst[A.shape[1]*index : A.shape[1]*(index + 1)]", **kwds)0.8682223120704293
    # @FHTMitchell 2 middling, short, very readable
    >>> timeit("np.array(lst).reshape(A.shape)", **kwds)
    1.0178500059992075
    # @anishtain4 slow, short, misleading
    >>> timeit("np.c_[lst].reshape(A.shape)", **kwds)
    2.458487769123167
    

    【讨论】:

    • 更简洁:A.flat[:]=lst
    • @hpaulj 酷,我完全没有意识到这一点。它是如何工作的?它似乎并不等价,小型阵列要快得多,大型阵列要慢得多。
    【解决方案2】:

    简单地做

    A[0] = lst[:3]
    A[1] = lst[3:]
    

    以编程方式,我想这已经完成了

    for index in range(A.shape[0]):
         A[index] = lst[A.shape[1]*index : A.shape[1]*(index + 1)]
    

    或者只是做

    A = np.array(lst, dtype=float).reshape((2, 3, 4))
    

    输出:

    [[[1. 2. 3. 0.]
      [3. 4. 6. 9.]
      [9. 5. 8. 5.]]
    
     [[1. 5. 4. 2.]
      [9. 7. 0. 5.]
      [4. 3. 2. 1.]]]
    

    【讨论】:

    • np.array、np.vstack、np,stack、np.c_ 等都是将这 6 个数组组合成一个 (6,4) 数组的完美方法。串联函数系列都采用数组列表,这正是lst 的含义。
    【解决方案3】:

    你可以用pythonic的方式来做:

    A=np.c_[lst].reshape((2,3,4))
    

    这不需要初始化数组A。

    我不会包含其他解决方案,因为循环只是冗余代码,对于较大的数组来说速度要慢得多。

    【讨论】:

    • 我可以理解不想使用reshape,这有点hacky。此外,初始化数组的规范方法是 np.array 和 np.asarray,而不是 np.c_ 和 np.r_。
    • @FHTMitchell 如果你知道你的形状,我不明白它怎么会是 hacky。这里np.array 做同样的事情,但它不能控制形状,你能提供一个参考谁决定它是规范的方式吗?上次我检查它们没有被弃用。编辑您的答案以包含另一个答案也不是很酷
    • 我也找不到reshape 的错误。但我可以在这种情况下使用c_,因为在这里它相当于对array 的一次非常模糊且缓慢的调用。它不自己做任何堆叠。如果lst 是一个元组,那么它会以错误的方式堆叠。
    • @anishtain4 我在你发布你的答案之前就编辑了我的答案......它们没有被弃用,但在 numpy 生态系统中很少。但是,np.c_ 明确用于沿最后一个轴连接数组,而不是用于初始化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2023-04-04
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    相关资源
    最近更新 更多