我刚刚发现了 Numpy 结构化数组,我发现它们非常强大。我的脑海中自然而然地出现了一个问题:我到底如何创建一个 Numpy 结构标量。让我告诉你我的意思。假设我想要一个包含一些数据的结构:
import numpy as np
dtype = np.dtype([('a', np.float_), ('b', np.int_)])
ar = np.array((0.5, 1), dtype=dtype)
ar['a']
Run Code Online (Sandbox Code Playgroud)
这给了我array(0.5)而不是0.5. 另一方面,如果我这样做:
import numpy as np
dtype = np.dtype([('a', np.float_), ('b', np.int_)])
ar = np.array([(0.5, 1)], dtype=dtype)
ar[0]['a']
Run Code Online (Sandbox Code Playgroud)
我明白了0.5,就像我想要的那样。这意味着它ar[0]不是数组,而是标量。是否有可能以比我所描述的更优雅的方式创建结构化标量?
Singleton 这个词不太合适,但我明白你想要的。
arr = np.array((0.5, 1), dtype=dtype)
Run Code Online (Sandbox Code Playgroud)
创建此数据类型的 0d 单元素数组。检查它的 dtype 和 shape。
arr.item()返回一个元组(0.5, 1)。阿苏测试arr[()]和arr.tolist()。
np.float64(0.5)使用 numpy 包装器创建一个浮点数。它与 类似,但不完全相同np.array(0.5)。他们的方法有些不同。
我不知道任何与复合数据类型类似的事情。
In [123]: dt = np.dtype('i,f,U10')
In [124]: dt
Out[124]: dtype([('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [125]: arr = np.array((1,2,3),dtype=dt)
In [126]: arr
Out[126]:
array((1, 2., '3'),
dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [127]: arr.shape
Out[127]: ()
Run Code Online (Sandbox Code Playgroud)
arr是一个 0d 1 元素数组。它可以通过以下方式建立索引:
In [128]: arr[()]
Out[128]: (1, 2., '3')
In [129]: type(_)
Out[129]: numpy.void
Run Code Online (Sandbox Code Playgroud)
该索引生成一个np.void对象。对 0d 浮点数组执行相同的操作将生成一个np.float对象。
但您不能使用np.void((1,2,3), dtype=dt)直接创建这样的对象(与 相比np.float(12.34))。
item是从数组中提取“标量”的正常方法。这里它返回一个元组,与我们用作创建输入的对象类型相同arr:
In [131]: arr.item()
Out[131]: (1, 2.0, '3')
In [132]: type(_)
Out[132]: tuple
Run Code Online (Sandbox Code Playgroud)
np.asscalar(arr)返回相同的元组。
对象和元组之间的一个区别np.void是,它仍然可以使用字段名称 进行索引,arr[()]['f0']而元组必须使用数字进行索引arr.item()[0]。仍然void有一个dtype,而元组没有。
fromrecords使recarray. 这类似于结构化数组,但允许我们将字段作为属性访问。它实际上可能是一个较旧的类,已合并到numpy,因此有np.rec前缀。我们大多数情况下使用结构化数组,尽管np.rec仍然有一些方便的功能。(实际上在numpy.lib.recfunctions):
In [133]: res = np.rec.fromrecords((1,2,3), dt)
In [134]: res
Out[134]:
rec.array((1, 2., '3'),
dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [135]: res.f0
Out[135]: array(1, dtype=int32)
In [136]: res.item()
Out[136]: (1, 2.0, '3')
In [137]: type(_)
Out[137]: tuple
In [138]: res[()]
Out[138]: (1, 2.0, '3')
In [139]: type(_)
Out[139]: numpy.record
Run Code Online (Sandbox Code Playgroud)
所以这产生了 anp.record而不是 a np.void。但这只是一个子类:
In [143]: numpy.record.__mro__
Out[143]: (numpy.record, numpy.void, numpy.flexible, numpy.generic, object)
Run Code Online (Sandbox Code Playgroud)
通过字段名称访问结构化数组会给出相应数据类型(和相同形状)的数组
In [145]: arr['f1']
Out[145]: array(2.0, dtype=float32)
In [146]: arr[()]['f1']
Out[146]: 2.0
In [147]: type(_)
Out[147]: numpy.float32
Run Code Online (Sandbox Code Playgroud)
Out[146]也可以用 来创建np.float32(2.0)。
ar[0]检查我对一维数组的评论:
In [158]: arr1d = np.array([(1,2,3)], dt)
In [159]: arr1d
Out[159]:
array([(1, 2., '3')],
dtype=[('f0', '<i4'), ('f1', '<f4'), ('f2', '<U10')])
In [160]: arr1d[0]
Out[160]: (1, 2., '3')
In [161]: type(_)
Out[161]: numpy.void
Run Code Online (Sandbox Code Playgroud)
因此arr[()],arr1d[0]对它们各自大小的数组执行相同的操作。同样arr2d[0,0],也可以写成arr2d[(0,0)]。