在 NumPy 中,数组不仅存储数据本身,还必须明确指定每个元素的数据类型。这一类型系统由 dtype(data type)对象统一管理。
与 Python 的动态类型不同,NumPy 数组中的元素通常具有统一的数据类型,并以固定字节数在内存中连续存储。这种设计使 NumPy 能够利用底层 C 语言实现高效的向量化计算,从而显著提升数值运算的性能。
dtype 不仅描述元素的数据类型,还包含字节大小、字节顺序以及字段结构等信息,是理解和控制数组行为的关键。
一、dtype 的基本概念
dtype 是 NumPy 中用于描述数组元素类型的核心对象。你可以通过数组的 .dtype 属性直接查看其数据类型:
ndarray.dtype
下面是一个简单的示例:
import numpy as np
a = np.array([1,2,3])
print(a.dtype)
输出:
int64
这表明该数组的元素类型为 64 位整数。
你可以在创建数组时,通过 dtype 参数显式指定类型:
np.array(data, dtype=...)
例如:
a = np.array([1,2,3], dtype=np.float64)
print(a.dtype)
输出:
float64
NumPy 的数据类型设计具有几个鲜明特点:
- 元素类型统一:数组内所有元素共享同一数据类型。
- 固定字节占用:每个元素占用固定大小的内存字节数。
- 内存连续存储:数据在物理内存中是连续排列的。
- 底层优化:运算可充分利用底层 C 语言优化甚至 SIMD 指令。
因此,dtype 的选择直接关系到数组的计算速度、内存消耗和数值精度。
NumPy 的 dtype 体系涵盖了丰富的数据类型,主要分类如下:
| 类型类别 |
示例 |
| 布尔 |
bool_ |
| 整数 |
int8, int16, int32, int64 |
| 无符号整数 |
uint8, uint16, uint32, uint64 |
| 浮点 |
float16, float32, float64(部分平台支持 float128) |
| 复数 |
complex64, complex128(部分平台支持 complex256) |
| 字符串 |
字节字符串 S Unicode 字符串 U |
| 对象 |
object_ |
| 时间 |
datetime64, timedelta64 |
| 结构化 |
structured dtype |
| 原始数据 |
void |
二、NumPy 的基本数值类型
NumPy 提供了一套独立于 Python 内置类型的、更精细的数值类型系统。
1. 整数类型
整数类型用于表示整型数值。
| 类型 |
字节 |
说明 |
int8 |
1 |
8 位有符号整数 |
int16 |
2 |
16 位有符号整数 |
int32 |
4 |
32 位有符号整数 |
int64 |
8 |
64 位有符号整数 |
uint8 |
1 |
无符号 8 位整数 |
uint16 |
2 |
无符号 16 位整数 |
uint32 |
4 |
无符号 32 位整数 |
uint64 |
8 |
无符号 64 位整数 |
示例:
a = np.array([1,2,3], dtype=np.int32)
print(a.dtype)
输出:int32
2. 浮点类型
浮点类型用于表示带小数的数值。
| 类型 |
字节 |
说明 |
float16 |
2 |
半精度浮点 |
float32 |
4 |
单精度浮点 |
float64 |
8 |
双精度浮点 |
示例:
a = np.array([1.5, 2.3, 4.8], dtype=np.float32)
print(a.dtype)
输出:float32
3. 复数类型
用于表示复数。
| 类型 |
说明 |
complex64 |
实部和虚部均为 float32 |
complex128 |
实部和虚部均为 float64 |
示例:
import numpy as np
a = np.array([1+2j, 3+4j], dtype=np.complex64)
print(a.dtype)
输出:complex64
4. 布尔类型
NumPy 的布尔 dtype 表示为 bool,其对应的 NumPy 标量类型为 np.bool_。
示例:
import numpy as np
a = np.array([True, False, True])
print(a.dtype)
输出:bool
np.bool_ 是用于表示单个布尔值的标量类型:
import numpy as np
b = np.bool_(True)
print(b) # True
print(type(b)) # <class 'numpy.bool_'>
当数组的 dtype 为 bool 时,其内部每个元素实际上都是 np.bool_ 类型的标量对象。
import numpy as np
a = np.array([True, False, True])
print(type(a[0])) # <class 'numpy.bool_'>
三、dtype 类型代码
除了完整的类型名称,NumPy 还支持一种更简短的表示方式——类型代码。它通常由 类型字母 + 字节数 组成。
常见类型代码对照表:
| 类型代码 |
等价类型 |
说明 |
i1 |
int8 |
8 位有符号整数 |
i2 |
int16 |
16 位有符号整数 |
i4 |
int32 |
32 位有符号整数 |
i8 |
int64 |
64 位有符号整数 |
u1 |
uint8 |
无符号 8 位整数 |
u2 |
uint16 |
无符号 16 位整数 |
u4 |
uint32 |
无符号 32 位整数 |
u8 |
uint64 |
无符号 64 位整数 |
f4 |
float32 |
单精度浮点 |
f8 |
float64 |
双精度浮点 |
c8 |
complex64 |
复数(两个 float32) |
c16 |
complex128 |
复数(两个 float64) |
示例:
import numpy as np
a = np.array([1,2,3], dtype="i4")
print(a.dtype) # int32
类型代码中常见的类型字母含义:
| 字母 |
含义 |
b |
布尔 |
i |
有符号整数 |
u |
无符号整数 |
f |
浮点数 |
c |
复数 |
S |
字节字符串 |
U |
Unicode 字符串 |
O |
Python 对象 |
M |
datetime64 |
m |
timedelta64 |
V |
void(原始数据) |
类型代码常用于以下场景:
- 快速指定 dtype:
dtype="f8"
- 定义结构化数组:
dtype=[("age","i4"),("score","f4")]
- 二进制数据解析:
np.fromfile("data.bin", dtype="i2")
- dtype 字符串表示:例如
dtype('<f8'),其中 < 表示小端序(little-endian),f8 表示 8 字节浮点数。
四、字节序
NumPy 的 dtype 还可以描述数据的字节顺序。
| 符号 |
含义 |
< |
little-endian(小端序) |
> |
big-endian(大端序) |
= |
本机字节序 |
示例:
import numpy as np
dt = np.dtype("<f8") # little-endian float64
print(dt)
NumPy dtype 的完整字符串格式是:字节序 + 类型 + 大小。
例如:
<i4 little-endian int32
>i4 big-endian int32
<f8 little-endian float64
- 小端序:低位字节存放在内存的低地址处。
- 大端序:高位字节存放在内存的低地址处。
理解字节序对于二进制文件读写和跨平台数据交换尤为重要。
五、其它数据类型
1. 字符串类型
NumPy 支持固定长度的字符串。
| 类型 |
说明 |
S |
字节字符串 |
U |
Unicode 字符串 |
示例:
import numpy as np
a = np.array(["apple", "banana"], dtype="U10")
print(a.dtype)
输出:<U10
说明:U10 表示最多 10 个 Unicode 字符,< 是字节序标记。
2. 时间类型
NumPy 提供了专门的时间数据类型。
-
datetime64:用于表示具体的日期和时间。
import numpy as np
a = np.array(["2026-01-01", "2026-01-02"], dtype="datetime64[D]") # [D] 表示单位为 day
print(a)
输出:['2026-01-01' '2026-01-02']
-
timedelta64:用于表示时间间隔。
import numpy as np
a = np.array([1,2,3], dtype="timedelta64[D]")
print(a)
输出:[1 2 3],数值代表以天为单位的时间间隔数量。
常用时间单位:
| 单位 |
含义 |
Y |
年 |
M |
月 |
D |
天 |
h |
小时 |
m |
分钟 |
s |
秒 |
ms |
毫秒 |
3. Python 对象类型
NumPy 也可以存储任意 Python 对象,此时 dtype 为 object。
import numpy as np
# 创建 object 类型数组
a = np.array([1, "hello", [1,2,3]], dtype=object)
print(a)
# 查看数组元素的类型
print(type(a[1]))
输出示例:
[1 'hello' list([1, 2, 3])]
<class 'numpy.object_'>
numpy.object_ 是用于封装任意 Python 对象的标量类型。也可以直接创建:
import numpy as np
x = np.object_("hello")
print(x) # hello
print(type(x)) # <class 'numpy.object_'>
需要注意的是,dtype 为 object 的数组不再是高效的数值数组:
- 每个元素存储的是 Python 对象引用。
- 计算速度远慢于普通数值数组。
- 通常只用于存放异构数据等特殊场景。
4. 结构化数据类型
NumPy 允许数组元素包含多个字段,类似于 C 语言中的结构体,这极大地增强了其处理表格型数据的能力。
import numpy as np
dtype = np.dtype([
("name", "U10"),
("age", "i4"),
("score", "f4")
])
data = np.array([
("艾婉婷", 18, 88.5),
("岳露珊", 19, 92.0)
], dtype=dtype)
print(data)
输出:
[('艾婉婷', 18, 88.5) ('岳露珊', 19, 92. )]
你可以通过字段名访问整列数据:
print(data["age"])
输出:[18 19]
结构化数组是处理带有混合类型字段的记录数据的利器。
六、类型转换
使用 astype() 方法可以进行数组数据类型的转换。注意,此操作会创建一个新的数组副本。
ndarray.astype(dtype)
示例:
import numpy as np
a = np.array([1,2,3], dtype=np.int32)
b = a.astype(np.float64)
print(b.dtype)
输出:float64
小结
dtype 是 NumPy 数组的灵魂,它精确定义了数组元素的数据类型、内存布局和存储结构。从基本的整数、浮点数,到复杂的复数和结构化类型,NumPy 提供了一套完备的数据类型系统来满足科学计算的各种需求。掌握如何在创建数组时指定 dtype,以及如何使用 astype() 进行转换,是高效利用 NumPy 进行数据处理和数值计算的基础。希望这篇指南能帮助你在 云栈社区 的编程之路上更进一步,更深入地理解数据背后的细节。