一、如何创建数组

NumPy 提供了多种创建数组的方法,最核心的是 np.array(),同时内置了许多快捷生成函数。

import numpy as np

# 1. 从列表、元组、range对象转换
np.array([1,2,3,4,5])          # 列表转数组
np.array((1,2,3,4,5))          # 元组转数组
np.array(range(5))             # range对象转数组
np.array([[1,2,3],[4,5,6]])    # 二维数组

# 2. 类似range的快捷生成
np.arange(8)                   # 类似range,返回数组 [0..7]
np.arange(1, 10, 2)            # 起始1,结束10,步长2

# 3. 等差/等比/全零/全一数组
np.linspace(0, 10, 11)         # 0到10之间生成11个等差元素
np.linspace(0, 10, 11, endpoint=False) # 不包含终点
np.logspace(0, 100, 10)        # 等比数列,10的幂次
np.zeros(3)                    # 全0数组
np.ones(3)                     # 全1数组
np.identity(3)                 # 单位矩阵(3x3)
np.diag([1,2,3,4])             # 对角矩阵

# 4. 随机数数组
np.random.randint(0, 50, 5)    # 0-50随机5个整数
np.random.randint(0, 50, (3,5))# 0-50随机数,形状3x5
np.random.rand(10)             # 10个0-1均匀分布随机数
np.random.standard_normal(5)   # 5个标准正态分布随机数

重点np.arange 和内置 range 的区别在于,arange 返回的是数组,支持更多数学运算。

二、修改数组中的元素

NumPy 中修改元素有两种本质区别:原地修改 vs 生成新数组

x = np.arange(8)

# 追加元素(返回新数组,不改变原数组)
np.append(x, 8)                # 末尾追加一个
np.append(x, [9,10])          # 末尾追加多个

# 原地修改(会改变原数组)
x[3] = 8                      # 下标直接赋值

# 插入元素(返回新数组)
np.insert(x, 1, 8)            # 在下标1处插入值8

# 二维数组的修改
x = np.array([[1,2,3],[4,5,6],[7,8,9]])
x[0, 2] = 4                   # 修改第0行第2列
x[1:, 1:] = 1                 # 切片批量修改:行≥1且列≥1的区域
x[1:, 1:] = [[1,2],[3,4]]     # 同时修改多个值(注意形状匹配)

三、数组与常量的运算

数组与常量进行运算时,会逐个元素进行计算(广播机制)。

x = np.array((1,2,3,4,5))

# 数组在前,常量在后:数组的每个元素与常量运算
x * 2    # 每个元素乘以2
x / 2    # 每个元素除以2
x // 2   # 整除
x ** 3   # 每个元素的三次方
x + 2    # 每个元素加2

# 常量在前,数组在后:注意运算结果不同
2 ** x   # 2的x次方(2^1, 2^2, 2^3...)
2 / x    # 2除以每个元素

四、数组与数组的运算

# 等长数组:对应位置元素运算
np.array([1,2,3]) + np.array([4,3,2])  # 逐元素相加

# 不等长但可广播:短的数组会“扩展”
a = np.array([1,2,3])
b = np.array([[1,2,3], [4,5,6], [7,8,9]])
c = a * b   # a的每个元素乘以b对应列的元素
a + b       # a的每个元素加b对应列的元素

广播原则:如果两个数组维度不同,NumPy 会尝试将较小的数组“广播”到与大数组兼容的形状。如果无法广播,则报错。

五、数组的排序

x = np.array([3, 1, 2, 4])

# 返回排序后的下标数组(不改变原数组)
np.argsort(x)   # 返回 [1, 2, 0, 3],对应 1->2->3->4

# 最大/最小值的下标
x.argmax()      # 3(最大值4的下标)
x.argmin()      # 1(最小值1的下标)

# 原地排序(改变原数组)
x.sort()        # x 变为 [1, 2, 3, 4]

关键理解argsort() 返回的是下标数组,可以通过 x[_] 取出排序后的原值。

六、数组的内积运算

内积 = 对应位置元素的乘积之和。

x = np.array([1, 2, 3])
y = np.array([4, 5, 6])

np.dot(x, y)      # 32
x.dot(y)          # 32
sum(x * y)        # 32
# 计算:1*4 + 2*5 + 3*6 = 32

七、比较两个数组

判断两个数组中对应位置的元素是否足够接近:

x = np.array([1, 2, 3, 4.001, 5])
y = np.array([1, 1.999, 3, 4.01, 5.1])

np.allclose(x, y)                  # 逐个比较,全为True则True
np.allclose(x, y, rtol=0.2)        # 设置相对误差
np.allclose(x, y, atol=0.2)        # 设置绝对误差
np.isclose(x, y)                   # 返回布尔数组,每个位置独立比较

八、访问数组中的元素

b = np.array([[1,2,3],[4,5,6],[7,8,9]])

# 基础访问
b[0]          # 第0行所有元素
b[0, 2]       # 第0行第2列的元素
b[0][2]       # 等价写法

# 列表索引(花式索引)
b[[0, 1]]                  # 第0行和第1行的所有元素
b[[0, 2, 1], [2, 1, 0]]   # 分别取 (0,2), (2,1), (1,0) 三个位置的元素

# 切片访问
a = np.arange(10)
a[::-1]      # 反向切片
a[::2]       # 隔一个取一个
a[:5]        # 前5个元素

九、修改数组形状

c = np.arange(25)
c.shape = 5, 5    # 变成5行5列的二维数组

# 切片组合访问
c[0, 2:5]         # 第0行,列下标[2,5)的元素
c[2:5, 2:5]       # 行和列同时切片,取子区域
c[:, 2]           # 第2列所有元素(冒号代表所有行)
c[:, [2, 4]]      # 第2列和第4列所有元素
c[[1, 3]]         # 第1行和第3行所有元素
c[[1, 3]][:, [2, 4]]  # 第1、3行的第2、4列元素

今日核心总结

  1. 数组创建np.array() 是最核心的转换方式,掌握 arangelinspacezeros/onesrandom 等快捷生成函数。

  2. 运算原则

    • 数组与常量:逐元素运算,注意“数组在前”和“常量在前”的结果差异
    • 数组与数组:等长直接算,不等长则广播(能广播则算,不能就报错)
  3. 排序诀窍

    • argsort() 返回的是下标数组,不是排序后的值
    • argmax/argmin 返回最大/最小值的下标
    • sort() 是原地排序,会改变原数组
  4. 访问与修改

    • 修改数组有“返回新数组”和“原地修改”两种方式,注意区分
    • 花式索引(列表索引)可以同时取多个任意位置的元素
    • 切片是视图,修改切片会影响原数组
  5. 形状变换shape 属性直接修改形状;使用 [:, 2] 这样的语法切出特定行列。

注:已经使用DeepSeek进行整理精简核心内容,些许不理解的配合个人笔记进行理解。

更多推荐