如何解读numpy中ndarray数组的order存储顺序参数?
发布于 作者:苏南大叔 来源:程序如此灵动~作为目前python
代码中强大又常见的第三方数组类型,ndarray
类型,在创建数组的时候有个order
参数,可以控制元素在内存中的存储顺序。就是说在ndarray
形成的时候,输入的元素的实际位置,受到order
参数的控制,控制其元素的实际摆放位置。
苏南大叔的"程序如此灵动"博客,记录苏南大叔的编程经验内容。本文测试环境:win10
,python@3.11.0
,numpy@1.24.2
。
以前有首歌叫做“都选C”来着吧?其实很适合本文,对于和ndarray
扯上关系的order
参数,选择C
是大概率没有问题的。选择F
大概率是会出一些意外的。
前文回顾
本文内容的正确理解,可能需要您了解如下内容:
- 如何定义一个
ndarray
:https://newsn.net/say/numpy-ndarray.html - 使用
range()
生成一个范围:https://newsn.net/say/ndarray-arange.html ndarray
类型的扁平化:https://newsn.net/say/ndarray-flatten.html- 使用
reshape()
重塑数组形状:https://newsn.net/say/ndarray-reshape.html zeros()
和ones()
生成ndarray
:https://newsn.net/say/numpy-zeros-ones.html
重要结论:order!!!
对于python
的ndarray
,相关选项就一个:fortran_order
!取值是True
或者False
!所以,不论本文中的后续内容如何说明,极有可能的真相就是:就是二分法,是不是按列读取!fortran_order
!
可以把ndarray
保存到.npy
或者.npz
文件里面,就可以看到其描述类似为:
{'descr': '<U1', 'fortran_order': False, 'shape': (2, 4), }
有哪些order?
可用的order
有四个,但是常见的就两个。
参数 | 用途 | 说明 |
---|---|---|
C | 按行读取 | 最常见 |
F | 按列读取 | 相对不常见 |
K | 按内存读取 | -- |
A | 按行或列读取 | 对于python 来说,A就等于C |
使用order
参数的函数有如下几个,默认order
参数都是C
。
numpy.copy()
numpy.ravel()
numpy.flatten()
numpy.reshape()
(无法使用K
)numpy.zeros()
numpy.ones()
- 其它
只有定义numpy.array()
中的order
默认是K
(内存)。
order
不影响ndarray
的视图
order
不影响ndarray
的视图。也就是说,无论order
写的是什么值,最终展现出来的视图(通俗的说,print
出来的数据)都是一样的。只是影响成员在内存中的存放顺序,但是这个对于大多数人来说,是无感的。
下面的代码中(不限于这些),虽然order
设置不同,但是,这些变量的打印值一模一样。
import numpy as np
a = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='C')
b = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='F')
c = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='K')
d = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='A')
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
输出:
a: [['苏' '南' '大' '叔']
['技' '术' '博' '客']]
b: [['苏' '南' '大' '叔']
['技' '术' '博' '客']]
c: [['苏' '南' '大' '叔']
['技' '术' '博' '客']]
d: [['苏' '南' '大' '叔']
['技' '术' '博' '客']]
使用.strides
可以做部分区分
因为实际情况下,order
参数A
效果等于C
,K
效果也很可能等于C
。所以,使用.strides
是可以区分F
的情况出来。
strides
:进展,步法。
正常情况下来说,一个元素占四个字节(也不一定,这里就是举个简单的例子。)
测试代码:
import numpy as np
a = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='C')
b = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='F')
c = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='K')
d = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='A')
print("C:", a.strides)
print("F:", b.strides)
print("K:", c.strides)
print("A:", d.strides)
输出:
C: (16, 4)
F: (4, 8)
K: (16, 4)
A: (16, 4)
可以看到:
order | 取值 | 第一维度(行)内存差值 | 第二维度(列)内存差值 |
---|---|---|---|
C/K/A | (16,4) | 4个元素*4个字节=16字节 | 4个字节 |
F | (4,8) | 4个字节 | 8个字节 |
查看内存中的实际排序
可以利用了数据扁平化函数的order='K'
参数来进行查看。[用魔法打败魔法]。
这里可以使用.zeval()
和.flatten()
来实现数据的扁平化,但是不能使用reshape(-1)
,会得到错误提示信息:
d2 = d.reshape(-1,order="K")
^^^^^^^^^^^^^^^^^^^^^^^
ValueError: order 'K' is not permitted for reshaping
参考文章:
测试order='C/K/A'
import numpy as np
a = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='C')
c = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='K')
d = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='A')
a2 = a.flatten(order="K")
print(a2, a2.strides)
c2 = c.flatten(order="K")
print(c2, c2.strides)
d2 = d.flatten(order="K")
print(d2, d2.strides)
输出:
['苏' '南' '大' '叔' '技' '术' '博' '客'] (4,)
['苏' '南' '大' '叔' '技' '术' '博' '客'] (4,)
['苏' '南' '大' '叔' '技' '术' '博' '客'] (4,)
测试order='F'
import numpy as np
b = np.array([["苏", "南", "大", "叔"], ["技", "术", "博", "客"]], order='F')
b2 = b.ravel(order="K")
print(b2, b2.strides)
# b2 = b.flatten(order="K")
# print(b2, b2.strides)
输出:
['苏' '技' '南' '术' '大' '博' '叔' '客'] (4,)
上面的代码显示:内存中的值是按着一列一列的顺序存储的。
import numpy as np
b0 = [["苏", "南", "大", "叔"], ["技", "术", "博", "客"]]
b = np.array(b0, order='F').swapaxes(1,0)
print(b, b.strides)
b2 = b.flatten(order="K")
print(b2, b2.strides)
输出:
[['苏' '技']
['南' '术']
['大' '博']
['叔' '客']] (8, 4)
['苏' '技' '南' '术' '大' '博' '叔' '客'] (4,)
这个代码显示:虽然中间值b
被转置了,但是内存中的存储顺序依然没有发生改变。
相关文章:
结论
可见,order
参数在定义的时候,没有什么大的影响的。但是对其成员进行读取的时候,根据order
的不同,可能会有不同的结果出现。
更多苏南大叔的python
经验文章,请点击:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。