python - 将具有特定结构的 1D 数组解码为 3D 或 4D 数组的最有效方法(使用 Python)
问题描述
我有一个由大约 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),第二个 x 代表 (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, channel) 切片
- 创建一个对帧求和的 (x, y, channel) 数组
我知道如何使用循环来做到这一点,但恐怕我会开始遇到内存或性能问题。即使我不为这个数据集,未来的数据集可能会更大,所以我想从一开始就以正确的方式去做。
我的问题是:有没有一种很好的 Pythonic、有效的方法来进行这种类型的数据转换?避免所有元素循环的东西?
我也很欣赏关于最佳实践的提示,以便在保持良好性能和管理内存的同时轻松处理数据。最好存储整个 4D 数据集并对其执行切片和操作,还是只存储 1D 数组并在需要进行某些计算时进行逐帧转换?鉴于数据非常稀疏,是否有另一种存储数据的方法,这样它会比 4D 数组占用更少的内存,但仍然可以轻松查看/访问/操作?
解决方案
我找到了一种方法,仍然有一个循环,但避免了所有元素的循环。我测量它比所有元素的循环快 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))和表示通道的列。必要时重塑它是微不足道的。
推荐阅读
- intellij-idea - 当内部操作开启时,“Go to implementation”键盘映射用于不同的目的
- python - 如何检查列表元素是否满足给定条件?
- angular - SonarQube 安全热点,在 Angular 中使用正则表达式
- eclipse - looking for a way to automatically create blocks in SysML Model
- python - 当尝试使用 selinum 进入下一页时,它会给出列表索引超出范围错误
- python - Discord.py 如何使命令适用于某些角色?
- powershell - Imagebox does not flip an image when needed with Powershell
- winapi - Can't see BlueetoothLE devices
- oracle-nosql - Oracle NoSQL数据库中的运算符BETWEEN和日期,怎么办?
- postgresql - Postgresql 12.5 "relation already exists" when using "create table if not exists"