【问题标题】:Flatten inner tuples inside 3D NumPy array and save to CSV as floats展平 3D NumPy 数组中的内部元组并作为浮点数保存到 CSV
【发布时间】:2021-07-07 19:04:27
【问题描述】:

当最里面的行包含混合类型的条目时,我想展平 3(/4) 维 NumPy 数组的最里面和最外面的轴:浮点数和浮点数的数组/元组。然后我想将其保存到一个 CSV 文件中,所有值都为 float64 类型。

have = [[[0.0 array([24.0,25.0]) 2.0 3.0]
         [4.0 array([26.0,27.0]) 6.0 7.0]
         [8.0 array([28.0,29.0]) 10.0 11.0]]

        [[12.0 array([30.0,31.0]) 14.0 15.0]
         [16.0 array([30.0,31.0]) 18.0 19.0]
         [20.0 array([30.0,31.0]) 22.0 23.0]]]

target = [[0.0 24.0 25.0 2.0 3.0]
              [4.0 26.0 27.0 6.0 7.0]
              [8.0 28.0 29.0 10.0 11.0]
              [12.0 30.0 31.0 14.0 15.0]
              [16.0 30.0 31.0 18.0 19.0]
              [20.0 30.0 31.0 22.0 23.0]]

np.savetxt('target.csv', target, delimiter=',')

【问题讨论】:

    标签: python arrays python-3.x numpy flatten


    【解决方案1】:

    您的问题使用 3D 数组的示例,其中数组元素指针位于中心索引处,但是现有答案不会直接应用于您的示例输入/输出,而无需进一步的重要步骤。这是一个解决方案,它以高效简洁的方式实现了您所要求的(并将概括)从您的示例到 CSV 文件的所有内容。

    首先让我们创建您的示例数组have

    >>> import numpy as np
    >>> have = np.arange(24).reshape(2,3,4).astype('object')
    >>> ins = np.arange(24,36)
    >>> c = 0
    >>> for i in range(2):
            for j in range(3):
                have[i][j][1] = np.array([ins[c], ins[c+1]])
                c += 2
    >>> print(have)                                      # The exact array as in the question.
    [[[0 array([24, 25]) 2 3]
      [4 array([26, 27]) 6 7]
      [8 array([28, 29]) 10 11]]
    
     [[12 array([30, 31]) 14 15]
      [16 array([32, 33]) 18 19]
      [20 array([34, 35]) 22 23]]]
    

    现在我们将创建一个新数组作为您的target 数组。

    # Axis 1 is not needed as output will be all rows
    #
    all_rows          = np.vstack(have)
    # Efficiently create dummy array of correct size
    #                              
    >>> target        = np.empty((have.shape[0]*have.shape[1], 4+1))
    # LHS floats in correct positions
    #
    >>> target[:,:1]  = all_rows[:,:1]
    # RHS floats in correct positions
    #                             
    >>> target[:,-2:] = all_rows[:,-2:]
    # Slicing at a single index converts each array to floats
    #
    >>> target[:,1:3] = np.vstack(all_rows[:,1])    
    >>> print(target)                                    # The exact array as in the question.
    [[ 0. 24. 25.  2.  3.]
     [ 4. 26. 27.  6.  7.]
     [ 8. 28. 29. 10. 11.]
     [12. 30. 31. 14. 15.]
     [16. 32. 33. 18. 19.]
     [20. 34. 35. 22. 23.]]
    

    这会生成一个数组 target,其中所有条目的类型都是 float64,因此我们可以完全按照您在问题中的建议将其保存到当前目录中的 CSV 文件中。

    >>> np.savetxt('target.csv', target, delimiter=',')
    

    还只是为了让您知道,您可以使用单个“反引号”而不是问题中使用的普通单引号在 Stack Overflow 上包含内联代码/亮点。这通常位于键盘上 Esc 键的正下方。

    【讨论】:

    • 这正是我想要的。我希望我能用赏金奖励这个答案。非常感谢!
    【解决方案2】:

    此代码应该适用于问题中的特定场景。

    1. 访问最里面的数组
    2. 检查每个元素的实例
    3. 如果是<class 'numpy.ndarray'> 类型,则调用.tolist() 将其转换为python 列表 并使用+ 运算符将列表合并到现有的内部列表中

    代码:

    import numpy as np
    have = [
        [
            [0.0, np.array([24.0,25.0]), 2.0, 3.0],
             [4.0, np.array([26.0,27.0]), 6.0, 7.0],
             [8.0, np.array([28.0,29.0]), 10.0, 11.0]
        ],
    
        [
            [12.0, np.array([30.0,31.0]), 14.0, 15.0],
             [16.0, np.array([30.0,31.0]), 18.0, 19.0],
             [20.0, np.array([30.0,31.0]), 22.0, 23.0]
        ]
    ]
    
    tar = []
    for i, e1 in enumerate(have):
        tar.append([])
        for j, e2 in enumerate(e1):
            temp = []
            for e3 in e2:
                if isinstance(e3, np.ndarray):
                    temp += e3.tolist()
                else:
                    temp.append(e3)
            tar[i].append(temp)
    
    print(tar)
    

    输出:

    [[[0.0, 24.0, 25.0, 2.0, 3.0],
     [4.0, 26.0, 27.0, 6.0, 7.0],
     [8.0, 28.0, 29.0, 10.0, 11.0]],
    
    [[12.0, 30.0, 31.0, 14.0, 15.0],
     [16.0, 30.0, 31.0, 18.0, 19.0], 
    [20.0, 30.0, 31.0, 22.0, 23.0]]]
    
    

    【讨论】:

    • 感谢您的回复。这有点复杂,您的 Axis 1 不在我的目标数组中。对于我在问题中提到的数百万行,“for”循环很慢。不过还是谢谢你,我已经了解了 .tolist 方法作为奖励。
    • @SO1999 是的,我同意这种方法可能会更慢。除此之外,输出与您在问题中提供的目标数组具有相同的结构。我没明白你说的那部分是什么意思。
    【解决方案3】:

    我认为可以公平地说,您的问题的核心是将 numpy.ndarrays 合并到现有的浮点数列表中,而不是对列表的外部维度进行操作。下面的代码解决了这个问题,以你的第一个内部列表为例:

    import numpy as np
    
    iList = [0.0, np.array([24.0,25.0]), 2.0, 3.0]
    
    newList = []
    for i in iList:
        if type(i) == np.ndarray:
            lList = i.tolist()
            for l in lList:
                newList.append(l)
        else:
            newList.append(i)
    

    如果您运行此测试代码,您可以确认所有结果现在都是浮点数:

    for x in newList:
        print(type(x))
    

    哪个输出:

    <class 'float'>
    <class 'float'>
    <class 'float'>
    <class 'float'>
    <class 'float'>
    

    保存到 CSV 在其他地方得到了很好的介绍。

    【讨论】:

    • 感谢您的回复。这适用于整个数组的一个子数组的一行 - 使用两个“for”循环将其应用于每个子子数组是否会在大规模(例如 >1M 行)上有效?
    • @SO1999,对不起,我不确定那个。如果您正在大规模地做类似的事情,并且您有多种外部循环的方法,那么可能值得尝试它们并使用“timeit”模块比较运行时。
    • 我比较了 100 万行不同响应的时间,“for”循环比接受的答案慢得多。不过感谢您的回复,我已经了解了 .tolist 方法作为奖励
    【解决方案4】:

    当您显示have 时,numpy 只知道它有一个 (2,4) 数组,其中一些条目是指向其他对象的指针(numpy 不知道它们是什么,但在您打印时访问它们的显示have)。因此,任何解决方案都需要收集这些其他数组以在其他地方重新分配它们,因为 numpy 不会提前知道所有数组的大小相同。

    import numpy as np
    
    have         = np.array([[np.array([1,2]),5],[np.array([3,4]),7]])
    target       = np.empty((2,3))      #Create some empty space
    target[:,2]  = have[:,1]            #Reassign all the float points to their locations
    target[:,:2] = np.vstack(have[:,0]) #Stack all the other arrays (assumes same size)
    

    【讨论】:

      猜你喜欢
      • 2022-10-01
      • 1970-01-01
      • 2019-09-13
      • 1970-01-01
      • 2018-07-09
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多