3.1 五种常用创建路径对比


文档摘要

3.1 五种常用创建路径对比 本节摘要:按需求分四类梳理 ndarray 的创建路径——数值已知用 array、占位填充用 zeros 与 ones、等差序列用 arange 与 linspace、随机模拟用 random 包,加上读文件载入共五条路。每条路的默认 dtype 与内存行为不同,创建时显式声明 dtype 是最便宜的保险。附决策表与 empty 的代价说明。 先想清楚你站在哪类需求前 写代码时最忌"逢创建就 array(列表)"。把需求分清楚,函数自然就选出来了: 五条路里最值得展开的是第二条:占位家族不止 zeros 与 ones。 占位家族的行为差异 empty 比 zeros 略快,因为它跳过清零。但注意:省的只是初始化那一步,通常只占数组生命周期成本的一小部分。

3.1 五种常用创建路径对比

本节摘要:按需求分四类梳理 ndarray 的创建路径——数值已知用 array、占位填充用 zeros 与 ones、等差序列用 arange 与 linspace、随机模拟用 random 包,加上读文件载入共五条路。每条路的默认 dtype 与内存行为不同,创建时显式声明 dtype 是最便宜的保险。附决策表与 empty 的代价说明。

先想清楚你站在哪类需求前

写代码时最忌"逢创建就 array(列表)"。把需求分清楚,函数自然就选出来了:

import numpy as np # 需求一:数值已经在手里(Python 列表、元组、范围) a = np.array([1, 2, 3], dtype=np.float64) print(a, a.dtype) # [1. 2. 3.] float64 # 需求二:先占位,稍后填充(初始化矩阵、累加缓冲) z = np.zeros((2, 3)) # 默认 float64 o = np.ones((3, 2), dtype=np.int32) print(z.dtype, o.dtype) # float64 int32 # 需求三:等差序列(坐标轴、索引、采样点) r = np.arange(0, 10, 2) # 起点 终点(不含) 步长 l = np.linspace(0, 1, 5) # 起点 终点(含) 个数 print(r) # [0 2 4 6 8] print(l) # [0. 0.25 0.5 0.75 1. ] # 需求四:随机数据(模拟、测试、初始化权重) rng = np.random.default_rng(seed=42) m = rng.random((2, 2)) # 0到1均匀分布 print(m.round(3)) # [[0.774 0.44 ] # [0.858 0.697]]

五条路里最值得展开的是第二条:占位家族不止 zeros 与 ones。

占位家族的行为差异

import numpy as np # zeros:分配后逐字节清零,内容确定 z = np.zeros((2, 2)) print(z) # 全 0 # empty:只分配不清零,内容是内存里的残留值 e = np.empty((2, 2)) print(e) # 输出不可预测,可能是 0,也可能是奇怪的旧值 # 例如:[[6.9e-310 6.9e-310] [0.0 0.0]] # full:统一填同一个值,做掩码初值很常用 f = np.full((2, 3), -1, dtype=np.int16) print(f) # [[-1 -1 -1] # [-1 -1 -1]] # zeros_like / ones_like / empty_like:照抄另一个数组的形状与类型 ref = np.zeros((2, 2), dtype=np.float32) g = np.ones_like(ref) print(g.dtype) # float32,形状类型一并继承

empty 比 zeros 略快,因为它跳过清零。但注意:省的只是初始化那一步,通常只占数组生命周期成本的一小部分。除非在循环里频繁开小数组,否则没必要为这点速度引入"内容不确定"的风险。真实案例:有人用 empty 后忘了完全填充,残留值恰好长得很像合法数据,模型训练许久才暴露异常。我的建议——empty 只在"立即全部覆写"的场合使用。

创建路径决策表

创建路径决策表

默认 dtype 的平台陷阱

array 与 zeros 不写 dtype 时的默认类型,随平台和输入变:

import numpy as np print(np.array([1, 2]).dtype) # int64(Linux/macOS) print(np.array([1.0, 2]).dtype) # float64,整数被提升 print(np.zeros(3).dtype) # float64 # Windows 上整数默认是 int32,同一份代码两端行为不同 # 显式声明是最便宜的跨平台保险: safe = np.zeros(3, dtype=np.int64)

混合类型的列表会被"就高不就低"地统一,Python 整数超范围时甚至直接跳 object。array 的类型推断是方便,不是承诺——数据要长期保存或参与精确控制内存的程序,一律显式声明 dtype。

💡 关键直觉:创建函数之间的差别不在"能不能造出数组",而在初始化策略与默认 dtype。选函数 = 选初始化策略;写 dtype = 选内存宽度。这两件事在创建那一刻定下,后面改起来都要付拷贝的代价(见下一节 astype)。

练习:用创建函数拼一个数据表

把四条路串起来用一遍,加深"按需求选函数"的肌肉记忆。背景:构造一张模拟成绩表——学号是等差序列、分数是正态随机、及格线是一列常量。

操作:

import numpy as np rng = np.random.default_rng(21) ids = np.arange(1001, 1021) # 需求三:等差学号 scores = rng.normal(72, 10, size=20).clip(0, 100) # 需求四:随机分数 pass_line = np.full(20, 60) # 需求二:常量列 table = np.column_stack([ids, scores.round(1), pass_line]) print(table[:4]) # [[1001. 71.3 60. ] # [1002. 65.2 60. ] # [1003. 84.9 60. ] # [1004. 58.6 60. ]] print("及格率:", (scores >= 60).mean().round(3)) # 输出示例:0.85

结果与解读:四类创建函数各司其职,column_stack(第 8 章细讲)把它们拼成一张表。如果最开始用 array 从嵌套列表转换,就得先在 Python 层造 20 行数据——既慢又违背"占位加填充"的思路。变式:把 pass_line 换成 np.zeros(20) 记录缺考标记,配合第 4 章的掩码即可做补考名单筛选。

本节要点回顾

  • 四类需求四条路:已知数值用 array;占位用 zeros/ones/full;等差用 arange/linspace;随机用 Generator
  • empty 有代价:不清零所以快一点,但残留值可能伪装成数据,只用于立即全量覆写
  • like 家族:zeros_like 等照抄形状与 dtype,改代码时不易失配
  • 显式 dtype:默认类型随平台变(Windows 整数 int32),跨平台代码必须声明
  • 转换成本:array 从列表转换要逐元素拆装箱,大列表慢且吃内存,数据量大时考虑后面章节的文件直读

下一节深入 dtype 体系:类型怎么命名、字宽如何取舍、astype 转型什么时候会静默丢数据。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U