将具有特定结构的1D数组解码为3D或4D数组(使用Python)的最有效方法

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

为了能够轻松地操纵这些数据并通过各个轴对其进行切片,最好将数据转换为4D数据集,或者能够即时创建3D切片。

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

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

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

这应该解释为

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,通道)数组

我知道如何使用循环执行此操作,但恐怕我会开始遇到内存或性能问题。即使我不使用此数据集,将来的数据集也可能更大,所以我想从一开始就以正确的方式来做。

我的问题是:是否存在一种不错的pythonic高效方法来进行这种类型的数据转换?有什么可以避免所有元素上的循环?

我也很欣赏有关最佳实践的技巧,这些技巧可简化数据处理并同时保持良好的性能和管理内存。是最好存储整个4D数据集并对其执行切片和操作,还是更好地只存储1D数组并在需要进行某些计算时逐帧转换?鉴于数据非常稀疏,是否还有另一种存储数据的方式,使其比4D阵列占用更少的内存,但仍然可以轻松查看/访问/操作?

zws138 回答:将具有特定结构的1D数组解码为3D或4D数组(使用Python)的最有效方法

我找到了一种方法,仍然可以循环,但是可以避免所有元素循环。我测得它比所有元素上的循环快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)),而列则表示通道。必要时重塑它很简单。

本文链接:https://www.f2er.com/3113873.html

大家都在问