numpy初级2-基本操作

Posted by Hilda on July 14, 2025

1.ndarray 的数据类型

NumPy ndarray 中的所有元素都必须是相同的数据类型(dtype)。这种固定类型的设计是 NumPy 实现高性能数值计算的基础。NumPy 提供了比 Python 内置类型更丰富、更精确的数值数据类型,包括不同位宽的整数、浮点数,以及布尔值、复数和字符串等。

Python 的列表可以存储不同类型的数据(例如 [1, "hello", 3.14]),因为它存储的是指向不同 Python 对象的引用。然而,NumPy 的 ndarray 追求的是内存效率和计算性能,它要求数组中的所有元素都具有相同的数据类型。这种同构性使得 NumPy 能够将数组数据连续地存储在内存中,从而实现高效的向量化操作和与底层 C/Fortran 库的无缝集成。

NumPy 提供了丰富的数据类型,这些类型通常以 numpy.dtype 对象表示,并且可以通过字符串简写来指定。

主要数据类型分类:

  1. 整数类型 (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:默认整数类型,通常是 int32int64,取决于操作系统和编译环境。
    • 拓展: 选择合适的整数类型可以节省内存。例如,如果知道数据范围在 0-255 之间,使用 uint8int64 可以节省 8 倍内存。
  2. 浮点数类型 (Floating-Point Types):
    • float16:16位半精度浮点数。精度较低,范围有限,但在某些深度学习场景中用于节省内存和加速计算。
    • float32:32位单精度浮点数。提供约 7 位十进制精度。
    • float64:64位双精度浮点数(默认)。提供约 15-17 位十进制精度,是科学计算中最常用的浮点类型。
    • float:默认浮点类型,通常是 float64
    • 拓展: 浮点数的精度和范围是有限的,理解浮点数表示的限制(如浮点数精度问题)对于数值计算至关重要。
  3. 字符串类型 (String Type):
    • 'S''bytes':字节字符串。例如 'S10' 表示长度为 10 的字节字符串。
    • 'U''str':Unicode 字符串。例如 'U10' 表示长度为 10 的 Unicode 字符串。
    • 重要: NumPy 的字符串是定长的。当创建或转换到字符串 dtype 时,NumPy 会根据最长字符串的长度来确定每个元素的存储空间。如果新字符串超过这个长度,它会被截断;如果短于这个长度,会用空字符填充。这与 Python 动态长度的字符串不同。
    • 拓展: 由于定长字符串的限制和效率问题,NumPy 数组通常不推荐直接存储大量可变长度的字符串。对于字符串操作,Python 原生字符串列表或 Pandas Series 更为合适。
  4. 其他常见类型:
    • bool:布尔类型,存储 TrueFalse
    • complex64 / complex128:复数类型,分别由两个 float32 / float64 组成。
    • object:Python 对象类型。数组元素可以是任意 Python 对象。这使得 ndarray 失去了 NumPy 的主要性能优势,因为它存储的是 Python 对象的引用,而不是连续的原始数据。

NumPy ndarray 的核心优势在于其内存布局。当指定一个 dtype 时,NumPy 会:

  1. 确定元素大小: dtype 明确地告诉 NumPy 数组中每个元素占用多少字节的内存(例如,int32 占用 4 字节,float64 占用 8 字节)。
  2. 连续内存分配: NumPy 会一次性分配一块足够大的连续内存区域,以容纳所有数组元素。例如,一个 (1000, 1000)float64 数组会分配 1000*1000*8 字节的内存。
  3. 直接内存访问: 由于元素大小固定且内存连续,NumPy 可以通过简单的指针算术(C 语言风格)快速定位到任何一个元素,而无需像 Python 列表那样进行多次引用查找。
  4. 优化计算: 这种连续内存布局使得 NumPy 能够利用 CPU 的缓存优势,并且可以高效地将计算任务分发给底层的 C/Fortran 库或 BLAS/LAPACK 等优化过的线性代数库。这些底层库是为处理固定类型、连续内存数据而高度优化的,从而实现了 Python 中难以匹敌的计算速度。

选择正确的 dtype 对于内存使用和计算性能至关重要。如果数据不需要高精度,使用较小的 dtype 可以显著减少内存占用,尤其是在处理大型数据集时。


1.以下关于 NumPy ndarray 数据类型的说法,哪项是正确的?

A. NumPy 数组可以像 Python 列表一样存储不同类型的数据。

B. int8 类型的整数可以存储从 -255 到 255 的值。

C. float32float64 占用更少的内存,但精度更高。

D. NumPy 的字符串 dtype 是定长的,如果字符串过长可能会被截断。

答案:D,int8:8位有符号整数,范围 [−128,127]。

2.创建一个 NumPy 数组,包含以下浮点数:[1.23456789, 9.87654321, 5.0]

  • 分别将其 dtype 指定为 float16float32float64
  • 打印每个数组及其 dtypeitemsize
  • 观察不同 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 非常重要:

  1. 优化内存: 如果你确定数据范围较小(例如,所有值都在 0-255 之间),可以指定 uint8int8 来大幅减少内存占用。
  2. 控制精度: 对于浮点数,你可以选择 float32 来节省内存(例如在深度学习中),或者坚持使用 float64 来保证最高精度。
  3. 避免意外推断: 有时 NumPy 的自动推断可能不符合你的预期。例如,一个包含整数和字符串的列表,NumPy 可能会将其推断为 object 类型,而不是你可能希望的特定数值类型(如果字符串可以转换为数字)。
  4. 数据类型统一: 在处理来自不同源的数据时,确保所有数组具有统一的 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