数据类型对象 (dtype)#

数据类型对象(numpy.dtype 类的实例)描述了如何解释与数组项对应的固定大小内存块中的字节.它描述了数据的以下方面:

  1. 数据的类型(整数、浮点数、Python对象等)

  2. 数据的大小(例如整数有多少字节)

  3. 数据的字节顺序(小端序大端序

  4. 如果数据类型是 结构化数据类型 ,即其他数据类型的聚合,(例如,描述由整数和浮点数组成的数组项),

    1. 结构体的”字段”名称是什么,通过它们可以如何 访问?

    2. 每个 字段 的数据类型是什么,以及

    3. 每个字段占用的内存块部分.

  5. 如果数据类型是一个子数组,它的形状和数据类型是什么.

要描述标量数据的类型,NumPy 中有几种 内置标量类型 用于各种精度的整数、浮点数等.从数组中提取的项目,例如通过索引,将是其类型与数组数据类型相关联的标量类型的 Python 对象.

请注意,标量类型不是 dtype 对象,尽管它们可以在需要数据类型规范的任何地方代替使用.

结构化数据类型是通过创建一个包含其他数据类型的 字段 的数据类型来形成的.每个字段都有一个名称,可以通过该名称 访问 .父数据类型应该足够大以包含其所有字段;父类型几乎总是基于允许任意项大小的 void 类型.结构化数据类型还可以在其字段中包含嵌套的结构化子数组数据类型.

最后,一个数据类型可以描述本身就是另一个数据类型项的数组的项.然而,这些子数组必须是固定大小的.

如果使用描述子数组的数据类型创建数组,则在创建数组时,子数组的维度将附加到数组的形状中.结构类型字段中的子数组行为不同,请参见 字段访问.

子数组总是具有C连续的内存布局.

示例

一个包含32位大端整数的简单数据类型:(有关构造的详细信息,请参见 指定和构建数据类型

>>> import numpy as np
>>> dt = np.dtype('>i4')
>>> dt.byteorder
'>'
>>> dt.itemsize
4
>>> dt.name
'int32'
>>> dt.type is np.int32
True

对应的数组标量类型是 int32.

示例

一个结构化数据类型,包含一个16字符的字符串(在字段’name’中)和一个包含两个64位浮点数的子数组(在字段’grades’中):

>>> import numpy as np
>>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
>>> dt['name']
dtype('<U16')
>>> dt['grades']
dtype(('<f8', (2,)))

这种数据类型的数组项被包装在一个 数组标量 类型中,该类型也有两个字段:

>>> import numpy as np
>>> x = np.array([('Sarah', (8.0, 7.0)), ('John', (6.0, 7.0))], dtype=dt)
>>> x[1]
('John', [6., 7.])
>>> x[1]['grades']
array([6.,  7.])
>>> type(x[1])
<class 'numpy.void'>
>>> type(x[1]['grades'])
<class 'numpy.ndarray'>

指定和构建数据类型#

每当在 NumPy 函数或方法中需要数据类型时,可以提供一个 dtype 对象或可以转换为该对象的内容.这种转换由 dtype 构造函数完成:

dtype(dtype[, align, copy])

创建一个数据类型对象.

可以转换为数据类型对象的内容如下所述:

dtype 对象

按原样使用.

None

默认数据类型:float64.

数组-标量类型

所有24个内置的 数组标量类型对象 都转换为关联的数据类型对象.这也适用于它们的子类.

请注意,并非所有数据类型信息都可以通过类型对象提供:例如,`flexible` 数据类型有一个默认的 itemsize 为 0,并且需要明确给定的尺寸才能有用.

示例

>>> import numpy as np
>>> dt = np.dtype(np.int32)      # 32-bit integer
>>> dt = np.dtype(np.complex128) # 128-bit complex floating-point number
通用类型

通用层次类型对象根据关联转换为相应的类型对象:

自 1.19 版本弃用: 这种对通用标量类型的转换已被弃用.这是因为在一个上下文中,例如 arr.astype(dtype=np.floating),即使 float32np.floating 的子类型,它也会将 float32 数组转换为 float64 数组,这可能是出乎意料的.

内置 Python 类型

几种 Python 类型在使用它们生成 dtype 对象时,相当于相应的数组标量:

注意 str_ 对应于 UCS4 编码的 Unicode 字符串.

示例

>>> import numpy as np
>>> dt = np.dtype(float)   # Python-compatible floating-point number
>>> dt = np.dtype(int)     # Python-compatible integer
>>> dt = np.dtype(object)  # Python object

备注

为了方便起见,所有其他类型都映射到 object_.代码应预期这些类型在未来可能会映射到一个特定的(新)dtype.

带有 .dtype 的类型

任何带有 dtype 属性的对象:将直接访问和使用该属性.该属性必须返回可以转换为 dtype 对象的内容.

可以转换几种字符串.识别的字符串可以以 '>' (大端序)、'<' (小端序) 或 '=' (硬件原生,默认) 为前缀,以指定字节顺序.

单字符字符串

每个内置数据类型都有一个字符代码(更新的 Numeric 类型代码),用于唯一标识它.

示例

>>> import numpy as np
>>> dt = np.dtype('b')  # byte, native byte order
>>> dt = np.dtype('>H') # big-endian unsigned short
>>> dt = np.dtype('<f') # little-endian single-precision float
>>> dt = np.dtype('d')  # double-precision floating-point number
数组协议类型字符串(参见 数组接口协议

第一个字符指定数据的种类,其余字符指定每个项目所占的字节数,除了Unicode,这里被解释为字符数.项目大小必须对应于一个现有的类型,否则会引发错误.支持的种类有

'?'

布尔值

'b'

(带符号的)字节

'B'

无符号字节

'i'

(带符号的)整数

'u'

无符号整数

'f'

浮点数

'c'

复杂浮点数

'm'

timedelta

'M'

datetime

'O'

(Python)对象

'S',``’a’``

以零结尾的字节(不推荐)

'U'

Unicode 字符串

'V'

原始数据 (void)

示例

>>> import numpy as np
>>> dt = np.dtype('i4')   # 32-bit signed integer
>>> dt = np.dtype('f8')   # 64-bit floating-point number
>>> dt = np.dtype('c16')  # 128-bit complex floating-point number
>>> dt = np.dtype('S25')  # 25-length zero-terminated bytes
>>> dt = np.dtype('U25')  # 25-character string

关于字符串类型的注意事项

为了向后兼容最初为支持 Python 2 编写的现有代码,``S`` 和 a 类型字符串是零终止的字节.对于 Unicode 字符串,请使用 U,`numpy.str_`.对于不需要零终止的有符号字节,可以使用 bi1.

带有逗号分隔字段的字符串

指定结构化数据类型格式的简写表示法是用逗号分隔的基本格式字符串.

在这种上下文中的基本格式是一个可选的形状说明符,后跟一个数组协议类型字符串.如果形状有多于一个维度,则需要括号.NumPy允许对该格式进行修改,即任何可以唯一标识类型的字符串都可以用于指定字段中的数据类型.生成的数据类型字段命名为 'f0', 'f1', …, 'f<N-1>',其中 N (>1) 是字符串中逗号分隔的基本格式的数量.如果提供了可选的形状说明符,则相应字段的数据类型描述一个子数组.

示例

  • 名为 f0 的字段包含一个 32 位整数

  • 名为 f1 的字段,包含一个 2 x 3 的 64 位浮点数子数组

  • 名为 f2 的字段,包含一个32位浮点数

    >>> import numpy as np
    >>> dt = np.dtype("i4, (2,3)f8, f4")
    
  • 名为 f0 的字段包含一个3字符的字符串

  • 名为 f1 的字段,包含形状为 (3,) 的子数组,包含 64 位无符号整数

  • 名为 f2 的字段,包含一个 3 x 4 的子数组,包含 10 个字符的字符串

    >>> import numpy as np
    >>> dt = np.dtype("S3, 3u8, (3,4)S10")
    
类型 字符串

任何 NumPy dtype 的字符串名称,例如:

示例

>>> import numpy as np
>>> dt = np.dtype('uint32')   # 32-bit unsigned integer
>>> dt = np.dtype('float64')  # 64-bit floating-point number
(flexible_dtype, itemsize)

第一个参数必须是一个被转换为零大小灵活数据类型对象的对象,第二个参数是一个提供所需项大小的整数.

示例

>>> import numpy as np
>>> dt = np.dtype((np.void, 10))  # 10-byte wide data block
>>> dt = np.dtype(('U', 10))   # 10-character unicode string
(fixed_dtype, shape)

第一个参数是任何可以转换为固定大小数据类型对象的对象.第二个参数是该类型的期望形状.如果形状参数是1,那么用于等同于固定dtype的数据类型对象.自NumPy 1.17起,此行为已被弃用,将来会引发错误.如果*shape*是一个元组,那么新的dtype定义了一个给定形状的子数组.

示例

>>> import numpy as np
>>> dt = np.dtype((np.int32, (2,2)))          # 2 x 2 integer sub-array
>>> dt = np.dtype(('i4, (2,3)f8, f4', (2,3))) # 2 x 3 structured sub-array
[(field_name, field_dtype, field_shape), ...]

obj 应该是一个字段列表,其中每个字段由长度为2或3的元组描述.(相当于 __array_interface__ 属性中的 descr 项.)

第一个元素,*field_name*,是字段名称(如果这是 '',则分配一个标准的字段名称,``’f#’``).字段名称也可以是一个由两个字符串组成的2元组,其中第一个字符串可以是”标题”(可以是任何字符串或unicode字符串)或字段的元数据(可以是任何对象),第二个字符串是”名称”,必须是有效的Python标识符.

第二个元素,*field_dtype*,可以是任何可以被解释为数据类型的东西.

可选的第三个元素 field_shape 包含此字段表示的数据类型数组的形状,该数据类型在第二个元素中.请注意,第三个参数等于 1 的 3 元组等价于 2 元组.

这种样式在 dtype 构造函数中不接受 align ,因为它假定所有的内存都由数组接口描述来处理.

示例

带有字段 ``big``(大端 32 位整数)和 ``little``(小端 32 位整数)的数据类型:

>>> import numpy as np
>>> dt = np.dtype([('big', '>i4'), ('little', '<i4')])

包含字段 R, G, B, A 的数据类型,每个字段都是一个无符号的 8 位整数:

>>> dt = np.dtype([('R','u1'), ('G','u1'), ('B','u1'), ('A','u1')])
{'names': ..., 'formats': ..., 'offsets': ..., 'titles': ..., 'itemsize': ...}

这种样式有两个必需键和三个可选键.*names* 和 formats 键是必需的.它们的值分别是等长的列表,包含字段名称和字段格式.字段名称必须是字符串,字段格式可以是 dtype 构造函数接受的任何对象.

当提供了可选键 offsetstitles 时,它们的值必须是与 namesformats 列表长度相同的列表.*offsets* 值是每个字段的字节偏移量列表(限制为 ctypes.c_int),而 titles 值是每个字段的标题列表(如果不需要该字段的标题,可以使用 None).*titles* 可以是任何对象,但当一个 str 对象将向字段字典添加一个以标题为键的条目,并引用包含标题作为额外元组成员的相同字段元组.

itemsize 键允许设置 dtype 的总大小,并且必须是一个足够大的整数,以使所有字段都在 dtype 内.如果构建的 dtype 是对齐的,则 itemsize 还必须能被结构对齐整除.总 dtype itemsize 限制为 ctypes.c_int.

示例

带有字段 r, g, b, a 的数据类型,每个字段都是一个 8 位无符号整数:

>>> import numpy as np
>>> dt = np.dtype({'names': ['r','g','b','a'],
...                'formats': [np.uint8, np.uint8, np.uint8, np.uint8]})

具有字段 r``b``(带有给定的标题)的数据类型,两者都是8位无符号整数,第一个在字段起始位置的字节位置0,第二个在位置2:

>>> dt = np.dtype({'names': ['r','b'], 'formats': ['u1', 'u1'],
...                'offsets': [0, 2],
...                'titles': ['Red pixel', 'Blue pixel']})
{'field1': ..., 'field2': ..., ...}

不鼓励这种用法,因为它与其他基于字典的构造方法有歧义.如果你有一个名为 ‘names’ 的字段和一个名为 ‘formats’ 的字段,将会产生冲突.

这种风格允许传入数据类型对象的 字段 属性.

obj 应包含引用 (数据类型, 偏移量)(数据类型, 偏移量, 标题) 元组的字符串或 Unicode 键.

示例

包含字段 ``col1``(字节位置0处的10字符字符串)、``col2``(字节位置10处的32位浮点数)和 ``col3``(字节位置14处的整数)的数据类型:

>>> import numpy as np
>>> dt = np.dtype({'col1': ('U10', 0), 'col2': (np.float32, 10),
...                'col3': (int, 14)})
(base_dtype, new_dtype)

在 NumPy 1.7 及更高版本中,这种形式允许 base_dtype 被解释为结构化 dtype.使用这种 dtype 创建的数组将具有底层 dtype base_dtype,但将具有从 new_dtype 获取的字段和标志.这对于创建自定义结构化 dtype 非常有用,如在 记录数组 中所做的那样.

这个形式也使得指定具有重叠字段的结构化数据类型成为可能,功能类似于C语言中的’union’类型.然而,这种用法是不鼓励的,更推荐使用union机制.

两个参数都必须可以转换为具有相同总大小的数据类型对象.

示例

32位整数,其前两个字节通过字段 real 解释为整数,后两个字节通过字段 imag 解释.

>>> import numpy as np
>>> dt = np.dtype((np.int32,{'real':(np.int16, 0),'imag':(np.int16, 2)}))

32位整数,被解释为包含8位整数的形状为``(4,)``的子数组:

>>> dt = np.dtype((np.int32, (np.int8, 4)))

32位整数,包含字段 r, g, b, a,将整数中的4个字节解释为四个无符号整数:

>>> dt = np.dtype(('i4', [('r','u1'),('g','u1'),('b','u1'),('a','u1')]))

检查数据类型#

当检查特定数据类型时,使用 == 比较.

示例

>>> import numpy as np
>>> a = np.array([1, 2], dtype=np.float32)
>>> a.dtype == np.float32
True

与Python类型相反,不应使用 is 进行比较.

首先,NumPy 将数据类型规范(可以传递给 dtype 构造函数的所有内容)视为等同于数据类型对象本身.这种等价性只能通过 == 处理,而不能通过 is 处理.

示例

一个 dtype 对象等于所有与之等价的数据类型规范.

>>> import numpy as np
>>> a = np.array([1, 2], dtype=float)
>>> a.dtype == np.dtype(np.float64)
True
>>> a.dtype == np.float64
True
>>> a.dtype == float
True
>>> a.dtype == "float64"
True
>>> a.dtype == "d"
True

其次,不能保证数据类型对象是单例的.

示例

不要使用 is 因为数据类型对象可能是也可能不是单例.

>>> import numpy as np
>>> np.dtype(float) is np.dtype(float)
True
>>> np.dtype([('a', float)]) is np.dtype([('a', float)])
False

dtype#

NumPy 数据类型描述是 dtype 类的实例.

属性#

数据的类型由以下 dtype 属性描述:

dtype.type

dtype.kind

一个字符代码('biufcmMOSUV' 中的一个),用于标识数据的一般类型.

dtype.char

每个21种不同的内置类型都有一个唯一的字符代码.

dtype.num

每种21种不同的内置类型都有一个唯一的编号.

dtype.str

此数据类型对象的数组协议类型字符串.

数据的大小依次由以下描述:

dtype.name

此数据类型的位宽名称.

dtype.itemsize

这个数据类型对象的元素大小.

此数据的大小端序:

dtype.byteorder

指示此数据类型对象的字节顺序的字符.

关于 结构化数据类型 中的子数据类型的信息:

dtype.fields

为此数据类型定义的命名字段字典,或 None.

dtype.names

字段名称的有序列表,如果没有字段则为 None.

对于描述子数组的数据类型:

dtype.subdtype

如果这个 dtype 描述的是一个子数组,则为元组 (item_dtype, shape),否则为 None.

dtype.shape

如果此数据类型描述的是一个子数组,则为子数组的形状元组,否则为 ().

提供附加信息的属性:

dtype.hasobject

布尔值,指示此dtype的任何字段或子dtype中是否包含任何引用计数的对象.

dtype.flags

描述如何解释此数据类型的位标志.

dtype.isbuiltin

整数,表示此数据类型与内置数据类型的关系.

dtype.isnative

布尔值,指示此数据类型的字节顺序是否为本机平台的字节顺序.

dtype.descr

__array_interface__ 数据类型的描述.

dtype.alignment

根据编译器,此数据类型所需的对其方式(字节).

dtype.base

返回子数组基本元素的数据类型,无论它们的维度或形状如何.

用户附加的元数据:

dtype.metadata

要么 None 要么是一个只读的元数据字典(mappingproxy).

方法#

数据类型有以下方法来改变字节顺序:

dtype.newbyteorder([new_order])

返回一个具有不同字节顺序的新数据类型.

以下方法实现了 pickle 协议:

dtype.__reduce__

pickle 的辅助工具

dtype.__setstate__

用于输入的实用方法:

dtype.__class_getitem__(item, /)

返回一个围绕 dtype 类型的参数化包装器.

比较操作:

dtype.__ge__(value, /)

返回 self>=value.

dtype.__gt__(value, /)

返回 self>value.

dtype.__le__(value, /)

返回 self<=value.

dtype.__lt__(value, /)

返回 self<value.