第一章——数组基础

数组的类型、维度与创建方式

NumPy 是科学计算的底层基石。理解“数组的类型与形状 + 向量化运算”这两件事,就足以支撑后续机器学习与深度学习的大部分代码。

本文将围绕两点展开:

  • 数组的数据类型(dtype)与类型转换(astype)
  • 数组的形状(shape)与变形(reshape)

配套示例均可直接运行,代码内已附简要注释。


1. 数组与 dtype:自动提升与显式转换

关键结论:

  • 同一个数组里元素的 dtype 必须一致;
  • 有浮点参与会“类型提升”为浮点;
  • astype 可进行显式类型转换(注意:转 int 会直接截断小数)。
import numpy as np  # 导入NumPy

# 纯整数数组 → dtype 为 int
arr1 = np.array([1, 2, 3])              # 创建整数类型的一维数组
print(arr1)                              # [1 2 3]

# 混合“浮点 + 整数” → 自动提升为 float
arr2 = np.array([1.0, 2, 3])            # 自动变为 float64
print(arr2)                              # [1. 2. 3.]

# 向整数数组写入浮点 → 会被截断为整数(仍是 int 数组)
arr3 = np.array([1, 2, 3])
arr3[0] = 100.9                          # 100.9 → 100
print(arr3)                              # [100   2   3]

# 向浮点数组写入整数 → 会保持为浮点
arr4 = np.array([1.0, 2, 3])
arr4[0] = 100                            # 100 → 100.0
print(arr4)                              # [100.   2.   3.]

# 显式类型转换(astype)
arr5 = arr1.astype(float)                # int → float
print(arr5)                              # [1. 2. 3.]

arr6 = arr2.astype(int)                  # float → int(截断小数)
print(arr6)                              # [1 2 3]

# 向量化算术会进行 dtype 对齐/提升
print(arr1 + 0.0)                        # 与浮点相加 → float
print(arr1 * 1.0)                        # 与浮点相乘 → float
print(arr1 / 1)                          # 除法默认产生浮点
print(arr1 + arr2)                       # 不同 dtype 相加 → 对齐为 float

要点回顾:

  • 明确 dtype 能避免“莫名其妙的小数被截断”;
  • 与标量/不同 dtype 运算时,NumPy 会自动广播并做类型提升。

2. 数组的形状 shape 与维度变换 reshape

关键结论:

  • shape 是理解张量维度的第一步;
  • reshape 可无拷贝地变形(视具体情况),-1 让 NumPy 自动推断某一维长度。
import numpy as np

# 构造不同维度的全 1 数组
arr1 = np.ones(3)                # 1D,长度 3
arr2 = np.ones((2, 3))           # 2D,形状 (2, 3)
arr3 = np.ones((2, 2, 3, 4))     # 4D,形状 (2, 2, 3, 4)

print(arr1.shape)  # (3,)
print(arr2.shape)  # (2, 3)
print(arr3.shape)  # (2, 2, 3, 4)

# 一维序列 → 按行重排
arr = np.arange(10)              # [0..9]
print(arr)                       # (10,)

arr_reshaped = arr.reshape(5, -1)  # 指定 5 行,列数自动推断为 2
print(arr_reshaped)                # 形状 (5, 2)

为什么 reshape(5, -1) 这么常见?

  • 机器学习里“每行一个样本、每列一个特征”。当我们有 10 个标量想堆成二维特征矩阵时,让 NumPy 自动算列数更方便。

3. 常见数组的创建方式(速记)

import numpy as np

# 从列表/嵌套列表创建
np.array([1, 2, 3])                  # 1D
np.array([[1, 2, 3]])                # 2D: (1, 3)
np.array([[1], [2], [3]])            # 2D: (3, 1)
np.array([[1, 2, 3], [4, 5, 6]])     # 2D: (2, 3)

# 递增序列
np.arange(10)                        # [0..9]
np.arange(1, 10)                     # [1..9]
np.arange(1, 10, 2)                  # [1,3,5,7,9]

# 同值数组
np.zeros(3)                          # [0, 0, 0]
np.ones((1, 3))                      # [[1, 1, 1]]
3.14 * np.ones((2, 3))               # 2x3 全 3.14

# 随机数组(补充)
np.random.random((2, 5))             # [0,1) 均匀分布
np.random.randint(10, 100, (1, 15))  # [10,100) 整数
np.random.normal(0, 1, (2, 3))       # N(0,1) 正态

实战建议:

  • 初学期把 np.array / np.arange / np.ones / np.zeros / np.random.* 熟练起来;
  • 建模时时刻记住 shape:数据是 (样本数, 特征数) 还是 (特征数,)

4. 小测验:一眼判断 dtype 与 shape

  1. np.array([1, 2., 3]) 的 dtype 是什么?为什么?
  2. 给定 a = np.arange(12),如何得到一个 (3, 4) 的矩阵?如何得到一个 (4, 3) 的?
  3. 下面两行输出是否一致?为什么?
np.array([1, 2, 3]) + 0.0
np.array([1., 2., 3.])

5. 这一章的“最小工作记忆”

  • dtype 决定“数怎么存、算出来是什么类型”;astype 做显式转换。
  • shape 决定“数怎么排布”;reshape 快速改变排布,-1 让 NumPy 自动算一维。
  • 向量化运算让使用者写少量代码就能对整批数据做计算,是 NumPy 的灵魂。

把这三点吃透,就能顺利迈向矩阵运算、广播机制、以及后续的机器学习/深度学习模型实现。

6. 常见坑位清单(务必收藏)

  • dtype 提升与截断

    • 混入浮点会自动升级为 float;astype(int) 会直接截断小数,不四舍五入。
    • 建议:金融/评估类数据保留小数,用 np.round(x, 2) 控制展示,计算保持 float。
  • 整数除法结果是浮点

    • np.array([1,2,3])/1 -> float。如果只要整除,显式用 //
  • 视图 vs 拷贝(reshape/slice 常见)

    • b = a.reshape(...) 常为“视图”(共享内存);b[0]=... 可能改动 a
    • 需要独立副本时:b = a.reshape(...).copy()b = a.copy()
  • 广播带来的“无声拉伸”

    • a(3,1) + b(1,4) 会广播成 (3,4);维度不匹配时错误不明显。计算前先 print(a.shape, b.shape)
  • 布尔索引返回拷贝

    • b = a[a>0] 是新数组;修改 b 不会改 a。若要原地改:a[a>0] = ...
  • 随机性不可复现

    • 调实验一定设种子:np.random.seed(42);新API也可用 rng = np.random.default_rng(42)
  • 比较浮点的陷阱

    • 避免 x == y;用 np.isclose(x, y, atol=1e-8)
  • 类型溢出

    • 小整数类型(如 np.int8)在累加时可能溢出,训练前统一 float32/float64 更稳。
  • in-place 与 dtype 冲突

    • a += 0.1a 是 int,会先计算为 float 再尝试写回 int,结果被截断。先 a = a.astype(float) 再算。
  • 内存布局(C/Fortran)

    • 与其他库交互(如 Fortran/BLAS)时,可能需要 np.ascontiguousarraynp.asfortranarray

7. 小测验参考答案

  • Q1:np.array([1, 2., 3]) 的 dtype?

    • A:float(包含浮点时自动类型提升)
  • Q2:a = np.arange(12) 如何得到 (3,4)(4,3)

    • A:a.reshape(3,4)a.reshape(4,3)
  • Q3:以下两行是否一致?为什么?

    • np.array([1, 2, 3]) + 0.0
      np.array([1., 2., 3.])
      
    • A:数值相同,dtype 都为 float。第一行因与浮点相加触发类型提升。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐