我想我可以做到: np.zeros((), dtype=dt).strides
,但是当 dtype 是像这样的大型数组类型时,这似乎效率不高('<f8', (200, 100))
。有没有办法直接从 dtype 到 numpy 中的跨步?
2 回答
您实际上可以在结构化数组中获得子数组的跨度,而无需创建“完整”数组。
根据文档,结构化数组中的子数组必须是连续的且按 C 顺序排列。请注意第一个示例上方的句子:
子数组始终具有 C 连续内存布局。
因此,对于没有字段的结构化数组,例如您的示例中的那个,您可以执行以下操作(作为不可读的单行):
import numpy as np
x = np.dtype(('<f8', (200, 100)))
strides = x.base.itemsize * np.r_[1, np.cumprod(x.shape[::-1][:-1])][::-1]
避免代码高尔夫:
shape = list(x.shape)
# First, let's make the strides for an array with an itemsize of 1 in C-order
tmp_strides = shape[::-1]
tmp_strides[1:] = list(np.cumprod(tmp_strides[:-1]))
tmp_strides[0] = 1
# Now adjust it for the real itemsize:
tmp_strides = x.base.itemsize * np.array(tmp_strides)
# And convert it to a tuple, reversing it back for proper C-order
strides = tuple(tmp_strides[::-1])
但是,当有多个字段时,这会变得更加复杂。一般来说,您需要进行适当的检查。例如:dtype 有shape
属性吗?它有字段吗?任何字段都有shape
属性吗?
我认为您正在谈论一个数组:
In [257]: dt=np.dtype([('f0',float, (200,100))])
In [258]: x=np.zeros((),dtype=dt)
数组本身是 0d 的一项。
In [259]: x.strides
Out[259]: ()
该项目的形状和步幅由 dtype 确定:
In [260]: x['f0'].strides
Out[260]: (800, 8)
In [261]: x['f0'].shape
Out[261]: (200, 100)
但是构造x
与构造具有相同形状的普通浮点数组有什么不同吗?
In [262]: y=np.zeros((200,100),float)
In [263]: y.strides
Out[263]: (800, 8)
y
如果没有实际构建它,你就无法获得潜力的长足。
Ipython whos 命令显示x
并y
占用大约相同的空间:
x ndarray : 1 elems, type `[('f0', '<f8', (200, 100))]`,
160000 bytes (156.25 kb)
y ndarray 200x100: 20000 elems, type `float64`,
160000 bytes (156.25 kb)
一个有趣的问题是这样的 a 是否x['f0']
具有 的所有属性y
。您可能可以阅读所有属性,但可能会限制您可以更改的属性。
您可以解析dtype:
In [309]: dt=np.dtype([('f0',float, (200,100))])
In [310]: dt.fields
Out[310]: mappingproxy({'f0': (dtype(('<f8', (200, 100))), 0)})
In [311]: dt[0]
Out[311]: dtype(('<f8', (200, 100)))
In [312]: dt[0].shape
Out[312]: (200, 100)
In [324]: dt[0].base
Out[324]: dtype('float64')
我没有看到or的strides
类似属性。可能有一些函数计算, 基于,但它可能是隐藏的。你可以搜索模块。这就是找到的地方。dt
dt[0]
numpy
strides
shape
np.lib.stride_tricks
as_strided
根据(200,100)
形状,并float64
占用 8 个字节,可以计算出正常(默认)步幅为(8*100, 8)
.
对于没有进一步嵌套的 dtype,这似乎有效:
In [374]: dt[0]
Out[374]: dtype(('<f8', (200, 100)))
In [375]: tuple(np.array(dt[0].shape[1:]+(1,))*dt[0].base.itemsize)
Out[375]: (800, 8)
让我们用这个 dtype 制作一个更复杂的数组
In [346]: x=np.zeros((3,1),dtype=dt)
In [347]: x.shape
Out[347]: (3, 1)
In [348]: x.strides
Out[348]: (160000, 160000)
它的步幅取决于形状和itemsize
。但是场的形状和步幅是 4d。我们可以说它们存在而不实际访问该字段吗?
In [349]: x['f0'].strides
Out[349]: (160000, 160000, 800, 8)
一个项目的步幅:
In [350]: x[0,0]['f0'].strides
Out[350]: (800, 8)
双重嵌套怎么样?
In [390]: dt1=np.dtype([('f0',np.dtype([('f00',int,(3,4))]), (20,10))])
In [391]: z=np.zeros((),dt1)
In [392]: z['f0']['f00'].shape
Out[392]: (20, 10, 3, 4)
In [393]: z['f0']['f00'].strides
Out[393]: (480, 48, 16, 4)
In [399]: (np.cumprod(np.array((10,3,4,1))[::-1])*4)[::-1]
Out[399]: array([480, 48, 16, 4], dtype=int32)
更正,字段的步幅是整个数组的步幅加上字段的步幅的组合。可以用 multifield dtype 看到
In [430]: dt=np.dtype([('f0',float, (3,4)),('f1',int),('f2',int,(2,))])
In [431]: x=np.zeros((3,2),dt)
In [432]: x.shape
Out[432]: (3, 2)
In [433]: x.strides
Out[433]: (216, 108)
In [434]: x['f0'].shape
Out[434]: (3, 2, 3, 4)
In [435]: x['f0'].strides
Out[435]: (216, 108, 32, 8)
(216,108)
是整个数组的跨步(itemsize 为 108),与f0
字段的跨步(32,8)
(itemsize 8)连接。