1. 概述

NumPy 中有三个描述数组数据的基本对象:

  • ndarrayN 维数组):存储多维数据,描述数据在内存中的布局,提供对数据的批量操作接口,如数学运算、索引、广播等。
  • dtype(数据类型对象):定义单个元素的内存布局和解释方式,支持基本类型、复合类型(结构化数组)和自定义类型。
  • Array Scalar(数组标量):通过索引访问单个数组元素时,返回一个与 dtype 对应的标量对象,提供与 Python 原生类型兼容的接口,同时保留 NumPy 类型特性。

它们之间的关系示意图:
在这里插入图片描述

图示内容解析:

  • ndarray 本身,包含元数据(Header)和数据缓冲区两部分。
  • 数组中元素的类型由一个单独的数据类型对象(dtype)指定,每个 ndarray 都与一个数据类型对象相关联。
  • 当访问数组中的单个元素时返回的数组标量 Python 对象。

在之前的篇章中,有提到 ndarrayNumPy 中最重要的一个类,它表示 N 维数组对象,该对象是用于存放同类型元素的多维数组。接下来我们全面的了解一下 ndarray ,在官方文档中主要提及了以下知识点:

  • 构造函数
  • 索引
  • 内存布局
  • 数组属性
  • 数组方法
  • 算术运算、矩阵乘法和比较操作
  • 特殊方法

2. 构造函数

ndarray 提供了一个底层的构造函数,适用于从现有缓冲区(如二进制数据)创建数组或高级优化场景。

函数定义:

np.ndarray(shape, dtype=float, buffer=None, offset=0, strides=None, order='C')

参数说明:

  • shape:数组维度。
  • dtype:元素类型。
  • buffer:从现有内存缓冲区(如 bytesbytearray)创建数组。
  • offset:缓冲区中的起始字节偏移量(默认为 0 )。
  • strides:自定义内存步长。
  • order:内存布局顺序。

简单示例:

# 原始数据
data = np.arange(6, dtype=np.int32).tobytes()  #  [0,1,2,3,4,5]

# 创建一个 2x3 数组,但每行间隔 8 字节(默认每行间隔 12 字节)
arr = np.ndarray(shape=(2, 3), dtype=np.int32, buffer=data, strides=(8, 4))

print(arr)
# 输出:
# [[0 1 2]
#  [2 3 4]]

⚠️ 提示: 大多数场景下,都是通过高层简洁的接口创建数组。

3. 索引

NumPy 根据索引对象的类型划分了三种索引方式:

  • 基础索引:只使用索引序号或切片。
  • 高级索引:使用整数数组或布尔数组。
  • 字段访问:通过字段名访问(结构化数组)。

⚠️ 提示: 之前已经介绍过了基础索引,后续会单独介绍其他的。

4. 内存布局

无论数组维度多高,数据最终存储在连续的一维内存块中,通过索引规则将 N 维坐标转换为内存中的偏移量。

涉及到的关键属性有:

  • shape:数组形状。
  • strides:每个维度上移动一个元素所需的字节数。
  • dtype:元素类型。

⚠️ 提示: 后续单独介绍内存布局。

5. 数组属性

数组属性是数组的核心组成部分,反映了数组本身的内在信息,NumPy 数组对象(ndarray)属性分为以下几类:

  • 内存布局
  • 数据类型
  • 其他属性
  • 数组接口协议
  • ctypes 外部函数接口

5.1 内存布局属性

属性名 类型 描述
ndarray.flags 属性 数组内存布局的信息(如连续性、读写权限等)
ndarray.shape 属性 数组维度组成的元组(例如 (3, 4) 表示 3 行 4 列的二维数组)
ndarray.strides 属性 遍历数组时,每个维度中步进的字节数组成的元组
ndarray.ndim 属性 数组的维度数量(如标量=0,向量=1,矩阵=2)
ndarray.data 属性 指向数组数据起始位置的 Python 缓冲区对象
ndarray.size 属性 数组中元素的总数(等于各维度大小的乘积)
ndarray.itemsize 属性 单个数组元素的字节长度(如 float64 类型的元素为 8 字节)
ndarray.nbytes 属性 数组元素消耗的总字节数(等于 size * itemsize
ndarray.base 属性 若数组共享其他对象的内存,则指向基对象;否则为 None

5.2 数据类型

属性名 类型 描述
ndarray.dtype 属性 数组元素的数据类型(如 int32, float64, 或自定义类型)

5.3 数组接口

属性名/方法名 类型 描述
__array_interface__ 属性 数组接口的 Python 端实现(提供元数据字典)
__array_struct__ 属性 数组接口的 C 端实现(用于与 C 扩展交互)

5.4 ctypes 接口

属性名 类型 描述
ndarray.ctypes 属性 简化数组与 ctypes 模块交互的对象(提供指针、形状等底层访问)

5.5 其他属性

属性名 类型 描述
ndarray.T 属性 转置数组的视图(等价于 np.transpose()
ndarray.real 属性 数组的实部(对复数数组有效)
ndarray.imag 属性 数组的虚部(对复数数组有效)
ndarray.flat 属性 数组的一维迭代器(可遍历所有元素)

⚠️ 提示: 之前已经介绍过常用的数组属性,没有介绍到的会后续涉及到的章节进行详细介绍。

6. 数组方法

数组对象(ndarray)包含多种操作方法,通常返回数组结果。按功能进行分类的方法有:

  • 数组转换方法
  • 形状操作
  • 元素选择与操作
  • 计算相关

6.1 数组转换

方法名 类型 描述
ndarray.item(*args) 方法 将数组的一个元素复制为标准 Python 标量并返回
ndarray.tolist() 方法 将数组转换为 a.ndim 层深度的嵌套 Python 列表
ndarray.tostring([order]) 方法 tobytes 的兼容性别名,行为完全相同
ndarray.tobytes([order]) 方法 生成包含数组原始数据字节的 Python bytes 对象
ndarray.tofile(fid[, sep, format]) 方法 将数组以文本或二进制(默认)形式写入文件
ndarray.dump(file) 方法 将数组的 pickle 序列化保存到指定文件
ndarray.dumps() 方法 返回数组的 pickle 序列化字符串
ndarray.astype(dtype[, ...]) 方法 创建转换到指定数据类型的数组副本
ndarray.byteswap([inplace]) 方法 交换数组元素的字节顺序(大小端转换)
ndarray.copy([order]) 方法 返回数组的深拷贝
ndarray.view([dtype][, type]) 方法 创建共享数据的新视图(可指定数据类型)
ndarray.getfield(dtype[, offset]) 方法 以特定类型返回数组的字段(内存布局操作)
ndarray.setflags([write, align, uic]) 方法 设置数组标志(可写性、内存对齐等)
ndarray.fill(value) 方法 用标量值填充整个数组

6.2 形状操作

方法名 类型 描述
ndarray.reshape(shape[, ...]) 方法 返回新形状的数组(数据不变)
ndarray.resize(new_shape[, refcheck]) 方法 原地修改数组形状和大小
ndarray.transpose(*axes) 方法 返回轴转置后的数组视图
ndarray.swapaxes(axis1, axis2) 方法 交换两个轴的数组视图
ndarray.flatten([order]) 方法 返回展平为一维的数组副本
ndarray.ravel([order]) 方法 返回展平为一维的数组视图
ndarray.squeeze([axis]) 方法 移除长度为 1 的轴

6.3 元素选择与操作

方法名 类型 描述
ndarray.take(indices[, axis, ...]) 方法 从指定索引处提取元素构建新数组
ndarray.put(indices, values[, mode]) 方法 将值按索引写入数组的扁平化视图
ndarray.repeat(repeats[, axis]) 方法 重复数组元素生成新数组
ndarray.choose(choices[, ...]) 方法 用索引数组从多个选择中构造新数组
ndarray.sort([axis, kind, order]) 方法 原地排序数组
ndarray.argsort([axis, ...]) 方法 返回排序后的元素索引
ndarray.partition(kth[, ...]) 方法 部分排序数组(使第 k 个元素处于有序位置)
ndarray.argpartition(kth[, ...]) 方法 返回部分排序的索引
ndarray.searchsorted(v[, ...]) 方法 查找元素应插入的位置以保持有序
ndarray.nonzero() 方法 返回非零元素的索引
ndarray.compress(condition[, ...]) 方法 按条件沿轴选择切片
ndarray.diagonal([offset, ...]) 方法 返回指定对角线元素

6.4 计算相关

方法名 类型 描述
ndarray.max([axis, out, ...]) 方法 沿轴返回最大值
ndarray.argmax([axis, out, ...]) 方法 返回最大值索引
ndarray.min([axis, out, ...]) 方法 沿轴返回最小值
ndarray.argmin([axis, out, ...]) 方法 返回最小值索引
ndarray.clip([min, max, out]) 方法 限制数组值在 [min, max] 范围内
ndarray.conj() 方法 返回所有元素的复共轭
ndarray.round([decimals, out]) 方法 返回四舍五入到指定小数位的数组
ndarray.trace([offset, ...]) 方法 沿对角线求和
ndarray.sum([axis, ...]) 方法 沿轴求和(支持指定数据类型防止溢出)
ndarray.cumsum([axis, ...]) 方法 沿轴返回累计和
ndarray.mean([axis, ...]) 方法 沿轴计算平均值
ndarray.var([axis, ...]) 方法 沿轴计算方差
ndarray.std([axis, ...]) 方法 沿轴计算标准差
ndarray.prod([axis, ...]) 方法 沿轴计算乘积
ndarray.cumprod([axis, ...]) 方法 沿轴返回累计乘积
ndarray.all([axis, ...]) 方法 检查是否所有元素为 True
ndarray.any([axis, ...]) 方法 检查是否有任意元素为 True

7. 算术运算、矩阵乘法与比较操作

基础规则:

  • 逐元素操作:所有算术和比较运算均为逐元素操作,返回新的 ndarray 对象。
  • 通用函数等价:每个操作均等价于对应的 NumPy 通用函数(ufunc)。

7.1 比较运算符

运算符(方法名) 等价表达式 描述
ndarray.__lt__(value) self < value 逐元素小于比较
ndarray.__le__(value) self <= value 逐元素小于等于比较
ndarray.__gt__(value) self > value 逐元素大于比较
ndarray.__ge__(value) self >= value 逐元素大于等于比较
ndarray.__eq__(value) self == value 逐元素等于比较
ndarray.__ne__(value) self != value 逐元素不等于比较

7.2 真值测试

方法名 描述
ndarray.__bool__() 当数组仅含 1 个元素时返回 True,否则抛出 ValueError

注意事项

  • 数组的真值测试会调用 ndarray.__bool__,如果数组中的元素数量不为 1,会引发错误,因为此类数组的真值是模糊的。在这种情况下,请使用 .any().all() 来明确表达您的意图。(如果您想检查数组是否为空,可以使用例如 .size > 0。)

7.3 单目运算符

运算符方法 类型 描述
ndarray.__neg__() 方法 逐元素取负:-self
ndarray.__pos__() 方法 逐元素取正:+self
ndarray.__abs__() 方法 逐元素取绝对值
ndarray.__invert__() 方法 逐元素按位取反:~self

7.4 算术运算符

运算符方法 类型 描述
ndarray.__add__(value) 方法 逐元素加法:self + value
ndarray.__sub__(value) 方法 逐元素减法:self - value
ndarray.__mul__(value) 方法 逐元素乘法:self * value
ndarray.__truediv__(value) 方法 逐元素真除法:self / value
ndarray.__floordiv__(value) 方法 逐元素地板除法:self // value
ndarray.__mod__(value) 方法 逐元素取模:self % value
ndarray.__divmod__(value) 方法 返回 (商, 余数) 元组
ndarray.__pow__(value[, mod]) 方法 逐元素幂运算(忽略第三个参数)
ndarray.__lshift__(value) 方法 逐元素左移位:self << value
ndarray.__rshift__(value) 方法 逐元素右移位:self >> value
ndarray.__and__(value) 方法 逐元素按位与:self & value
ndarray.__or__(value) 方法 逐元素按位或:self | value
ndarray.__xor__(value) 方法 逐元素按位异或:self ^ value

注意事项

  • pow 的第三个参数会被忽略(底层 ufunc 仅接受两个参数)。
  • 不支持反向运算符(如 __radd__),需通过 __array_ufunc__ 自定义行为。

7.5 复合赋值运算

运算符方法 类型 描述
ndarray.__iadd__(value) 方法 原地加法:self += value
ndarray.__isub__(value) 方法 原地减法:self -= value
ndarray.__imul__(value) 方法 原地乘法:self *= value
ndarray.__itruediv__(value) 方法 原地真除法:self /= value
ndarray.__ifloordiv__(value) 方法 原地地板除法:self //= value
ndarray.__imod__(value) 方法 原地取模:self %= value
ndarray.__ipow__(value) 方法 原地幂运算:self ​**​= value
ndarray.__ilshift__(value) 方法 原地左移位:self <<= value
ndarray.__irshift__(value) 方法 原地右移位:self >>= value
ndarray.__iand__(value) 方法 原地按位与:self &= value
ndarray.__ior__(value) 方法 原地按位或:self |= value
ndarray.__ixor__(value) 方法 原地按位异或:self ^= value

7.6 矩阵乘法

运算符方法 类型 描述
ndarray.matmul(value) 方法 矩阵乘法:self @ value

8. 特殊方法

8.1 标准库函数支持

方法名 类型 描述
ndarray.__copy__() 方法 实现 copy.copy() 的浅拷贝逻辑
ndarray.__deepcopy__(memo) 方法 实现 copy.deepcopy() 的深拷贝逻辑
ndarray.__reduce__() 方法 序列化数组(pickling 支持)
ndarray.__setstate__(state) 方法 反序列化数组(unpickling 支持)

8.2 基本定制方法

方法名 类型 描述
ndarray.__new__(*args, ​**kwargs) 方法 构造新数组的工厂方法
ndarray.__array__([dtype]) 方法 返回自身引用(当 dtype 匹配时)或副本
ndarray.__array_wrap__(array) 方法 返回与自身类型相同的数组视图

8.3 容器协议实现

方法名 类型 描述
ndarray.__len__() 方法 返回数组长度(第一维大小)
ndarray.__getitem__(key) 方法 实现索引操作 self[key]
ndarray.__setitem__(key, value) 方法 实现赋值操作 self[key] = value
ndarray.__contains__(key) 方法 实现成员检测 key in self

8.4 类型转换方法

方法名 类型 描述
ndarray.__int__() 方法 转换为整型(仅单元素数组有效)
ndarray.__float__() 方法 转换为浮点型(仅单元素数组有效)
ndarray.__complex__() 方法 转换为复数型(仅单元素数组有效)

8.5 字符串表示

方法名 类型 描述
ndarray.__str__() 方法 返回用户友好字符串表示(如 print(arr)
ndarray.__repr__() 方法 返回开发者调试用字符串表示

8.6 类型工具方法

方法名 类型 描述
ndarray.__class_getitem__(item) 方法 创建参数化类型包装器(用于类型注解)
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐