【问题标题】:Most efficient way for decoding 1D array with specific structure to 3D or 4D array (with Python)将具有特定结构的 1D 数组解码为 3D 或 4D 数组的最有效方法(使用 Python)
【发布时间】:2020-03-08 16:44:52
【问题描述】:

我有一个由大约 63M 个整数元素组成的 1D 数组,它代表一个 4D 数据集,轴为 x、y、通道、帧(所有正整数)。数据集的形状为 (512, 512, 4069, 239)。该数据集代表一个 X 射线光谱流,其中 x 和 y 是电子束光栅位置索引,每个通道代表一个 X 射线能量箱。样本被扫描多次,每一帧代表这样一个(x,y,通道)数据集。

为了能够轻松地操作此数据并通过各个轴对其进行切片,最好将数据转换为 4D 数据集或能够动态创建 3D 切片。

一维数组中的数据结构如下:每个元素要么是一个非常大的整数 x(大约 65000),要么是一个表示通道索引的整数(最大为 4069)。数组中存储的每个x对应一个扫描位置(x,y),所以第一个x代表(0,0),第二个(1,0),等等。扫描网格的形状为 512x512 像素,因此一旦达到 (511,0),下一个 x 对应于 (0, 1)。如果遇到 x 以外的其他值,则表示与这些值对应的通道在与前面的 x 对应的光束位置 (x,y) 处接收到计数。一旦超过索引 (511,511),下一帧开始。该阵列非常稀疏,因为在每一帧中总共只有大约 3000 个 X 射线计数,分布在 4069 个通道上。所以一维数组基本上是 239 帧,每帧用 512x512 + ~3000 个整数表示,全部串在一起。

为了说明,一维数据集可能看起来像

[65000, 65000, 1, 65000, 65000, 65000, 2, 3, 65000, 2, 2, 65000, 65000, ...]

这应该被解释为

Frame 1

       | Channel
x y    | 1 2 3 ... 4069
_____________________________
0 0    | 0 0 0
1 0    | 1 0 0
2 0    | 0 0 0
3 0    | 0 0 0
4 0    | 0 1 1
5 0    | 0 2 0
6 0    | 0 0 0
7 0    | 0 0 0
...    |
511 511|

Frame 2
...

Frame 239
...

我想做什么:

  • 重新创建完整的 4D 数据集以查看它是否适合内存并可以使用。我怀疑它需要的内存量是一维数组所需内存量的 4069 倍。
  • 动态创建一帧的 (x , y, 通道) 切片
  • 创建一个对帧求和的 (x, y, channel) 数组

我知道如何使用循环来做到这一点,但我担心我会开始遇到内存或性能问题。即使我不为这个数据集,未来的数据集可能会更大,所以我想从一开始就以正确的方式去做。

我的问题是:有没有一种很好的 Pythonic 高效的方法来进行这种类型的数据转换?避免所有元素循环的东西?

我还希望获得有关易于处理数据同时仍保持良好性能和管理内存的最佳做法的提示。最好存储整个 4D 数据集并对其执行切片和操作,还是只存储 1D 数组并在需要进行某些计算时进行逐帧转换?鉴于数据非常稀疏,是否有另一种存储数据的方法,这样它会比 4D 数组占用更少的内存,但仍然可以轻松查看/访问/操作?

【问题讨论】:

    标签: python arrays memory transformation large-data


    【解决方案1】:

    我找到了一种方法,仍然使用循环,但避免了所有元素的循环。我测量它比所有元素的循环快约 5 倍,所以我想我会分享。关键是使用 numpy.argwhere 找到计数所在的索引,我发现这比遍历所有元素要快得多。查找这些计数应该映射到哪个像素索引也可以通过矢量化方式完成。

    from scipy.sparse import dok_matrix
    import numpy as np
    
    def convert_stream_to_sparse(d1d: np.ndarray, dim: tuple, dv: int = 65535):
    
        #Initialize an array with the dimensions: total size * the number of channels
        temp = dok_matrix(dim, dtype=np.int16) 
    
        #find the indexes where counts are registered (!= the counting number)
        cinx = np.argwhere(d1d!=dv)[:,0] 
        #calc the pixel index to which these counts must be mapped
        pixind = cinx - np.arange(len(cinx)) - 1 
    
        #loop over the list of counts and put them in the right bin
        for i, j in zip(cinx, pixind): 
            chan = d1d[i] #the channel number = the value stored at the index
            temp[j, chan] += 1 #increment the right entry
    

    这会产生一个稀疏矩阵,其中行表示位置(连同有关扫描区域和帧数的信息,每行表示唯一的 (x,y,frame))和表示通道的列。必要时重新调整它是微不足道的。

    【讨论】:

      猜你喜欢
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多