跳转到内容

ndarray、shape 与 dtype

计算机基础 · NumPy

前置知识:容器、字符串与切片

本章目录

本章学习目标

  • 解释数组的维度、形状与数据类型
  • 选择正确的创建与转换方法
  • 检查整数溢出、缺失值与空数组

一、数值数组与 Python 列表

ndarray 是由数据缓冲区和元信息组成的多维数组;shape 说明各轴长度,dtype 说明一个元素如何解释,strides 描述沿各轴移动需要跨多少字节。普通数值数组通常使用统一类型,方便底层一次处理很多元素。Python 列表保存对象引用,可以混合类型,[1,2]*3 表示重复列表,NumPy 数组乘三则表示每个元素相乘,两者不能按外观相似就当作相同结构。

本模块约定二维表行是样本、列是变量,例如 [[10,100],[20,200],[30,300]] 的 shape 是 (3,2),ndim 为二,size 为六。大小不是行数,维度也不是元素数量。一维数组 (3,) 没有单独的“行向量”或“列向量”轴,若需要列向量应显式转换为 (3,1)。课程常规 API 按 NumPy 2.4.4 验证,版本号变化时优先核对锁定环境而非凭最新文档猜行为。

二、创建数组与序列间隔

np.array 从嵌套序列创建数组,zeros、ones、full 按给定形状初始化,避免未初始化内存被误读。arange 适合按固定步长生成半开区间,整数场景直观;浮点步长会受精度影响,要求固定点数且包含两个端点时优先使用 linspace。例如零到一的五个点应为零、四分之一、二分之一、四分之三和一,明确点数比反复累加小数更可靠。

reshape 改变形状但不改变元素个数,六个数可以变成两行三列,不能变成四行两列。使用一个负一可推断该轴长度,例如 reshape(2,-1) 推断为三;它不表达任意缺失维度。二维嵌套列表每行长度应一致,不规则嵌套数据应先清洗,不应随意使用 object 数组掩盖结构问题。empty 适合随后完整写入的缓冲区,不应把其中未知值当作初始零。

三、dtype 决定精度和范围

np.array 会根据输入推断类型,例如整数与浮点混合通常转为浮点;混入字符串可能让整个数组成为文本,之后不能执行预期数值计算。指定 dtype 能固定契约,但转成整数会截去小数,不等于四舍五入,也不能把 NaN 当正常整数。对于缺失数值,浮点数组可以用 NaN,布尔数组可以另设有效掩码;是否填零取决于业务,零值和缺失并非同义。

NumPy 的固定宽度整数会溢出,例如 int8 可表示负一百二十八到一百二十七,一百二十加一百二十无法装入该类型。Python int 的任意精度不能直接推及数组。用 np.iinfo 和 np.finfo 观察范围,累计前根据最大数量与单值上界选择足够宽的类型。float32 比 float64 少占一半数据字节,但有效精度较低,许多小数也不是精确值;需根据误差要求选择。

四、数据形状和缺失是入口检查

读取上游数据后先检查 ndim、shape、dtype、有限值数量以及必要的单位。空数组 shape=(0,2) 仍是合法二维结构,可用于表达零行两列,但均值没有观测基础;不能仅验证 ndim==2 就开始训练。np.isfinite 排除 NaN 和正负无穷,np.isnan 仅检测 NaN,两者回答的问题不同。判断数组是否为空用 size==0,不要写 if array,多个元素的真值含义不明确。

pandas 转为 NumPy 时常丢掉列名和索引,数组不会按标签自动对齐,因此必须把列顺序写入接口。学习阶段手工创建的两列矩阵容易记住含义,项目中则要随数组保存特征名单。不能将编号、日期和金额一起强转为 float 来获得单一矩阵;先选择真正需要运算的数值列,并对类别字段使用明确编码,日期字段另行处理。

五、从元信息理解程序结果

配套代码展示二维数组、均匀网格、缺失掩码、整数范围和空表,输出 shape、ndim、size、dtype 及 nbytes。nbytes 只统计元素缓冲区大小,不包含所有 Python 对象和引用开销;object 数组的 nbytes 更不能代表每个对象占用的总内存。不要凭这个数字断言整个进程只有这么多内存。

做实验时先在纸上写出形状和数值,再运行。把 float64 改为 float32 比较 nbytes,观察精度但不机械判断越小越好;把一个值换成字符串观察 dtype 变化。面试答题应从数据模型讲起:每个轴是什么、元素类型能装什么、是否缺失、哪些字段被排除。只有把输入结构讲清楚,后面的广播、线性代数和 PyTorch Tensor 才不会成为形状猜谜。

完整示例与实际输出

import numpy as np
X=np.array([[10,100],[20,200],[30,300]],dtype=np.float64)
assert (X.shape,X.ndim,X.size)==((3,2),2,6)
print('metadata',X.shape,X.ndim,X.size,str(X.dtype),X.nbytes)
grid=np.linspace(0,1,5)
assert np.allclose(grid,[0,.25,.5,.75,1])
print('grid',grid.tolist())
missing=np.array([1.,np.nan,np.inf])
assert np.isfinite(missing).tolist()==[True,False,False]
print('finite',np.isfinite(missing).tolist())
limits=np.iinfo(np.int8)
assert (limits.min,limits.max)==(-128,127)
print('int8 range',limits.min,limits.max)
empty=np.empty((0,2),dtype=float)
assert empty.size==0 and empty.shape==(0,2)
print('empty shape',empty.shape)
assert np.array([1,'2']).dtype.kind=='U'

实际运行通过CPU Python execution.

metadata (3, 2) 2 6 float64 48
grid [0.0, 0.25, 0.5, 0.75, 1.0]
finite [True, False, False]
int8 range -128 127
empty shape (0, 2)

五道自测:先回答,再核对

01 · shape=(3,2) 的 ndim 和 size 分别是多少?

查看提示

轴数与元素乘积。

查看参考答案

ndim=2,size=6。

02 · 一维数组 (3,) 是否等于 (3,1)?

查看提示

是否具有第二个轴?

查看参考答案

不等;前者只有一轴,后者是三行一列。

03 · 为何 linspace 常比浮点 arange 更适合固定网格?

查看提示

点数和端点。

查看参考答案

linspace 直接指定点数与端点;浮点 arange 的累进和终点可能受精度影响。

04 · int8 中一百二十加一百二十为何危险?

查看提示

最大值是多少?

查看参考答案

超过127,固定宽度类型无法容纳,可能溢出;应选择更宽类型。

05 · np.isfinite 与 np.isnan 有何不同?

查看提示

无穷也需要检查。

查看参考答案

isfinite 排除 NaN 与正负无穷,isnan 只标记 NaN。

两项动手任务

任务 1 · 创建两行三列 float32 的全一矩阵,打印 nbytes 并与 float64 比较。

提示

nbytes=元素数×每元素字节。

完整参考解答与检查方式

float32 为二十四字节,float64 为四十八字节,仅计数组数据缓冲。

import numpy as np
a=np.ones((2,3),dtype=np.float32)
b=a.astype(np.float64)
assert a.nbytes==24 and b.nbytes==48
print(a.shape,a.dtype,a.nbytes,b.nbytes)

任务 2 · 验证二维数值输入非空且全部有限;演示正常、空数组和 NaN 被如何处理。

提示

结构合法不等于可用于估计。

完整参考解答与检查方式

显式拒绝没有样本或包含非有限值的输入。

import numpy as np
def validate(X):
    X=np.asarray(X,dtype=float)
    if X.ndim!=2 or X.shape[0]==0 or X.shape[1]==0 or not np.isfinite(X).all():
        raise ValueError('need nonempty finite matrix')
    return X
assert validate([[1,2]]).shape==(1,2)
for bad in [np.empty((0,2)),[[1,np.nan]]]:
    try:
        validate(bad)
    except ValueError:
        print('rejected',np.shape(bad))
    else:
        raise AssertionError('must reject')

官方资料与掌握状态

完成两项任务后,按独立完成程度记录。状态会尽量保存在当前浏览器,可导出备份。

动手任务记录

掌握状态与复习

关掉资料独立完成后记 A;提示后完成记 B;需要重学记 C。

记录尽量保存在当前浏览器,建议定期导出备份。