Python:将3D列主序张量转换为行主序
咱先把这几个高维数组存储顺序的问题掰扯清楚,毕竟超过二维之后,确实容易绕晕~
1. scipy.io是否会自动处理列主序到行主序的转换?
答案是会自动处理!Matlab用的是列主序(也就是Fortran order,对应NumPy里的order='F'),而NumPy数组默认是行主序(C order,order='C')。scipy.io的loadmat函数在读取Mat文件时,会自动把Matlab的列主序数组转换成NumPy的行主序数组,而且会严格保证元素的逻辑位置和原Matlab数组一致,你完全不用手动去做这一步转换。除非你特意修改了loadmat的一些特殊参数(比如struct_as_record或squeeze_me)导致数组形状意外变化,但核心的存储顺序转换是默认完成的。
2. 若不会,有没有比结合ravel和reshape更好的3D张量转换方法?
当然有!如果你真遇到了需要手动转换的特殊场景(比如自己构造了列主序数组,或者读取时没自动转换的极端情况),NumPy提供了更直接的工具函数:
np.ascontiguousarray(arr):把任意存储顺序的数组转换成行主序(C连续)的数组,一步到位,不用自己拆成ravel再reshape,既简洁又不容易出错。np.asfortranarray(arr):反过来,把数组转换成列主序(Fortran连续)的数组。
对比你提到的ravel+reshape方法,这两个函数本质上做的是同样的事,但更直观——你不用手动指定ravel和reshape的order参数,函数内部已经帮你处理了高维数组的维度对应关系,省心很多。
3. 若没有更好方法,能否编程确定转换后张量的合理形状?
首先得纠正你示例里的问题:你用b.ravel(order='F').reshape(b.shape)得到奇怪结果,是因为你用列主序展开后,又用默认的行主序去reshape成原来的形状,相当于内存里的元素排列是列主序的,但你用行主序的规则去划分维度,结果肯定乱套。
正确的做法是:当你用某个order展开数组后,reshape时必须用相同的order参数,这样才能保证元素的逻辑位置和原数组一致。比如:
import numpy as np lst3d = [[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]], [[13, 14, 15], [17, 18, 19], [21, 22, 23], [25, 26, 27]]] b = np.array(lst3d) # 列主序展开 + 列主序reshape,结果和原数组一致 b_ravel_F = b.ravel(order='F') b_reshape_F = b_ravel_F.reshape(b.shape, order='F') print(b_reshape_F)
回到“确定合理形状”的问题:其实不管是几维数组,转换存储顺序的时候,逻辑形状是不需要改变的。存储顺序只是元素在内存中的排列方式,而数组的形状(比如你的示例里的(2,4,3))是逻辑上的维度划分,转换顺序只是调整元素的内存排列,逻辑维度完全可以保持和原数组一致。你觉得原形状不合适,只是因为reshape时没对应上order参数,导致维度划分和内存排列不匹配而已。
内容的提问来源于stack exchange,提问作者mdoc-2011

