1.ndarray 的数据类型
NumPy ndarray
中的所有元素都必须是相同的数据类型(dtype)。这种固定类型的设计是 NumPy 实现高性能数值计算的基础。NumPy 提供了比 Python 内置类型更丰富、更精确的数值数据类型,包括不同位宽的整数、浮点数,以及布尔值、复数和字符串等。
Python 的列表可以存储不同类型的数据(例如 [1, "hello", 3.14]
),因为它存储的是指向不同 Python 对象的引用。然而,NumPy 的 ndarray
追求的是内存效率和计算性能,它要求数组中的所有元素都具有相同的数据类型。这种同构性使得 NumPy 能够将数组数据连续地存储在内存中,从而实现高效的向量化操作和与底层 C/Fortran 库的无缝集成。
NumPy 提供了丰富的数据类型,这些类型通常以 numpy.dtype
对象表示,并且可以通过字符串简写来指定。
主要数据类型分类:
- 整数类型 (Integer Types):
int8
:8位有符号整数,范围 [−128,127]。uint8
:8位无符号整数,范围 [0,255]。int16
:16位有符号整数,范围 [−32768,32767]。uint16
:16位无符号整数,范围 [0,65535]。int32
:32位有符号整数,范围 [−2147483648,2147483647]。uint32
:32位无符号整数,范围 [0,4294967295]。int64
:64位有符号整数,范围 [−9223372036854775808,9223372036854775807]。uint64
:64位无符号整数,范围 [0,18446744073709551615]。int
:默认整数类型,通常是int32
或int64
,取决于操作系统和编译环境。- 拓展: 选择合适的整数类型可以节省内存。例如,如果知道数据范围在 0-255 之间,使用
uint8
比int64
可以节省 8 倍内存。
- 浮点数类型 (Floating-Point Types):
float16
:16位半精度浮点数。精度较低,范围有限,但在某些深度学习场景中用于节省内存和加速计算。float32
:32位单精度浮点数。提供约 7 位十进制精度。float64
:64位双精度浮点数(默认)。提供约 15-17 位十进制精度,是科学计算中最常用的浮点类型。float
:默认浮点类型,通常是float64
。- 拓展: 浮点数的精度和范围是有限的,理解浮点数表示的限制(如浮点数精度问题)对于数值计算至关重要。
- 字符串类型 (String Type):
'S'
或'bytes'
:字节字符串。例如'S10'
表示长度为 10 的字节字符串。'U'
或'str'
:Unicode 字符串。例如'U10'
表示长度为 10 的 Unicode 字符串。- 重要: NumPy 的字符串是定长的。当创建或转换到字符串
dtype
时,NumPy 会根据最长字符串的长度来确定每个元素的存储空间。如果新字符串超过这个长度,它会被截断;如果短于这个长度,会用空字符填充。这与 Python 动态长度的字符串不同。 - 拓展: 由于定长字符串的限制和效率问题,NumPy 数组通常不推荐直接存储大量可变长度的字符串。对于字符串操作,Python 原生字符串列表或 Pandas Series 更为合适。
- 其他常见类型:
bool
:布尔类型,存储True
或False
。complex64
/complex128
:复数类型,分别由两个float32
/float64
组成。object
:Python 对象类型。数组元素可以是任意 Python 对象。这使得ndarray
失去了 NumPy 的主要性能优势,因为它存储的是 Python 对象的引用,而不是连续的原始数据。
NumPy
ndarray
的核心优势在于其内存布局。当指定一个dtype
时,NumPy 会:
- 确定元素大小:
dtype
明确地告诉 NumPy 数组中每个元素占用多少字节的内存(例如,int32
占用 4 字节,float64
占用 8 字节)。- 连续内存分配: NumPy 会一次性分配一块足够大的连续内存区域,以容纳所有数组元素。例如,一个
(1000, 1000)
的float64
数组会分配1000*1000*8
字节的内存。- 直接内存访问: 由于元素大小固定且内存连续,NumPy 可以通过简单的指针算术(C 语言风格)快速定位到任何一个元素,而无需像 Python 列表那样进行多次引用查找。
- 优化计算: 这种连续内存布局使得 NumPy 能够利用 CPU 的缓存优势,并且可以高效地将计算任务分发给底层的 C/Fortran 库或 BLAS/LAPACK 等优化过的线性代数库。这些底层库是为处理固定类型、连续内存数据而高度优化的,从而实现了 Python 中难以匹敌的计算速度。
选择正确的
dtype
对于内存使用和计算性能至关重要。如果数据不需要高精度,使用较小的dtype
可以显著减少内存占用,尤其是在处理大型数据集时。
1.以下关于 NumPy ndarray
数据类型的说法,哪项是正确的?
A. NumPy 数组可以像 Python 列表一样存储不同类型的数据。
B. int8
类型的整数可以存储从 -255 到 255 的值。
C. float32
比 float64
占用更少的内存,但精度更高。
D. NumPy 的字符串 dtype
是定长的,如果字符串过长可能会被截断。
答案:D,
int8
:8位有符号整数,范围 [−128,127]。
2.创建一个 NumPy 数组,包含以下浮点数:[1.23456789, 9.87654321, 5.0]
。
- 分别将其
dtype
指定为float16
、float32
和float64
。 - 打印每个数组及其
dtype
和itemsize
。 - 观察不同
dtype
下浮点数的精度变化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
"""
float16 2
float32 4
float64 8
"""
import numpy as np
list1 = [1.23456789, 9.87654321, 5.0]
arr1 = np.array(list1, dtype="float16")
arr2 = np.array(list1, dtype="float32")
arr3 = np.array(list1, dtype="float64")
print(arr1.dtype, arr1.itemsize)
print(arr2.dtype, arr2.itemsize)
print(arr3.dtype, arr3.itemsize)
2.数组创建时指定数据类型
在使用 numpy.array()
函数创建 ndarray
时,可以通过 dtype
参数显式指定数组中元素的数据类型。这允许你精确控制内存使用和数值精度,并覆盖 NumPy 的默认类型推断。
当你不指定 dtype
参数时,NumPy 会根据输入数据自动推断出最合适的数据类型。例如,如果输入是整数,它通常会推断为 int64
;如果包含浮点数,则推断为 float64
。然而,在以下情况下,显式指定 dtype
非常重要:
- 优化内存: 如果你确定数据范围较小(例如,所有值都在 0-255 之间),可以指定
uint8
或int8
来大幅减少内存占用。 - 控制精度: 对于浮点数,你可以选择
float32
来节省内存(例如在深度学习中),或者坚持使用float64
来保证最高精度。 - 避免意外推断: 有时 NumPy 的自动推断可能不符合你的预期。例如,一个包含整数和字符串的列表,NumPy 可能会将其推断为
object
类型,而不是你可能希望的特定数值类型(如果字符串可以转换为数字)。 - 数据类型统一: 在处理来自不同源的数据时,确保所有数组具有统一的
dtype
可以简化后续操作。
3.asarray
转换时指定数据类型
numpy.asarray()
函数用于将输入转换为 ndarray
。与 numpy.array()
类似,它也可以通过 dtype
参数指定数据类型。但 asarray()
的一个关键特性是,如果输入已经是具有相同 dtype
和顺序的 ndarray
,它将不会创建副本,而是返回对原始数组的引用(视图),从而提高内存效率。
1
2
3
4
5
6
"""
array([1, 2, 3, 4])
"""
l1 = [1, 2, 3, 4]
arr1 = np.asarray(l1)
arr1
1
2
3
4
5
6
7
"""
array([[1., 1., 1.],
[1., 1., 1.]])
"""
arr2 = np.ones((2, 3))
arr3 = np.asarray(arr2)
arr3
4.数据类型转换 astype
ndarray.astype()
是一个 ndarray
对象的方法,用于将数组中的元素从当前数据类型转换为指定的新数据类型,并返回一个新的数组。这是一个显式的数据类型转换操作。
astype()
方法是 NumPy 中进行数据类型转换的常用且推荐的方式。
1
2
3
4
5
6
7
8
"""
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]], dtype=float32)
"""
arr = np.zeros((3, 4), dtype=int)
arr = arr.astype("float32")
arr