展平 3D NumPy 数组中的内部元组并作为浮点数保存到 CSV

Posted

技术标签:

【中文标题】展平 3D NumPy 数组中的内部元组并作为浮点数保存到 CSV【英文标题】:Flatten inner tuples inside 3D NumPy array and save to CSV as floats 【发布时间】: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=',')

【问题讨论】:

【参考方案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】:

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

    访问最里面的数组 检查每个元素的实例 如果是<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)

【讨论】:

以上是关于展平 3D NumPy 数组中的内部元组并作为浮点数保存到 CSV的主要内容,如果未能解决你的问题,请参考以下文章

展平和取消展平 numpy 数组的嵌套列表

展平 NumPy 数组列表?

Numpy 数组:连接展平和添加维度

Numpy 展平 RGB 图像数组

numpy 多维数组的存取

如何在不使用 NumPy 复制的情况下展平多维数组的轴?