NumPy 入门教程

18 阅读19分钟

NumPy 入门教程

目录


什么是 NumPy

NumPy(Numerical Python)是 Python 中用于科学计算的基础库,提供了高性能的多维数组对象和用于处理这些数组的工具。

核心特点

  • ndarray:高效的多维数组对象
  • 广播功能:对不同形状的数组进行算术运算
  • 数学函数:丰富的线性代数、傅里叶变换、随机数等功能
  • C/Fortran 集成:底层使用 C 语言实现,性能卓越
  • 生态基础:Pandas、SciPy、Matplotlib、Scikit-learn 等库的基础

为什么使用 NumPy?

特性Python 列表NumPy 数组
性能快 10-100 倍
内存占用大占用小
功能基础丰富的数学函数
向量化不支持支持
广播不支持支持
# 性能对比示例
import numpy as np
import time

# Python 列表
start = time.time()
result_list = [x**2 for x in range(1000000)]
print(f"列表耗时: {time.time() - start:.4f}秒")

# NumPy 数组
start = time.time()
result_array = np.arange(1000000) ** 2
print(f"NumPy耗时: {time.time() - start:.4f}秒")

安装 NumPy

方法一:通过 Anaconda 安装

NumPy 已预装在 Anaconda 中,无需额外安装。

# 验证安装
python -c "import numpy; print(numpy.__version__)"

方法二:通过 pip 安装

pip install numpy

导入 NumPy

import numpy as np

# 查看版本
print(np.__version__)

约定俗成:始终使用 import numpy as np 作为标准导入方式。


NumPy 数组基础

ndarray 对象

NumPy 的核心是 ndarray(N-dimensional array)对象,它是一个多维数组。

import numpy as np

# 从列表创建数组
arr = np.array([1, 2, 3, 4, 5])
print(arr)          # [1 2 3 4 5]
print(type(arr))    # <class 'numpy.ndarray'>

数组维度

# 0维数组(标量)
scalar = np.array(42)
print(scalar.ndim)  # 0

# 1维数组(向量)
vector = np.array([1, 2, 3, 4, 5])
print(vector.ndim)  # 1

# 2维数组(矩阵)
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
print(matrix.ndim)  # 2

# 3维数组
tensor = np.array([[[1, 2], [3, 4]],
                   [[5, 6], [7, 8]]])
print(tensor.ndim)  # 3

数组创建

从现有数据创建

import numpy as np

# 从列表创建
arr1 = np.array([1, 2, 3, 4, 5])

# 从元组创建
arr2 = np.array((1, 2, 3, 4, 5))

# 从嵌套列表创建二维数组
arr3 = np.array([[1, 2, 3],
                 [4, 5, 6],
                 [7, 8, 9]])

# 指定数据类型
arr4 = np.array([1, 2, 3], dtype=np.float64)
arr5 = np.array([1, 2, 3], dtype=np.int32)

常用创建函数

zeros - 全零数组
# 创建全零数组
zeros_1d = np.zeros(5)              # [0. 0. 0. 0. 0.]
zeros_2d = np.zeros((3, 4))         # 3x4 的零矩阵
zeros_3d = np.zeros((2, 3, 4))      # 2x3x4 的零数组

# 指定数据类型
zeros_int = np.zeros(5, dtype=int)  # [0 0 0 0 0]
ones - 全一数组
# 创建全一数组
ones_1d = np.ones(5)                # [1. 1. 1. 1. 1.]
ones_2d = np.ones((3, 4))           # 3x4 的全一矩阵
full - 填充指定值
# 创建填充指定值的数组
full_arr = np.full((3, 4), 7)       # 3x4 的数组,所有元素为 7
arange - 范围数组
# 类似 Python 的 range
arr1 = np.arange(10)                # [0 1 2 3 4 5 6 7 8 9]
arr2 = np.arange(2, 10)             # [2 3 4 5 6 7 8 9]
arr3 = np.arange(2, 10, 2)          # [2 4 6 8]
arr4 = np.arange(0, 1, 0.1)         # [0.  0.1 0.2 ... 0.9]
linspace - 等间距数组
# 在指定区间内生成等间距的点
arr1 = np.linspace(0, 10, 5)        # [ 0.   2.5  5.   7.5 10. ]
arr2 = np.linspace(0, 1, 100)       # 0到1之间的100个等间距点

# 不包含终点
arr3 = np.linspace(0, 10, 5, endpoint=False)  # [0. 2. 4. 6. 8.]
eye / identity - 单位矩阵
# 创建单位矩阵
eye_arr = np.eye(4)                 # 4x4 单位矩阵
identity_arr = np.identity(3)       # 3x3 单位矩阵
random - 随机数组
# 随机数组(详见后文随机数生成部分)
rand_arr = np.random.rand(3, 4)     # 0-1 之间的均匀分布
randn_arr = np.random.randn(3, 4)   # 标准正态分布
randint_arr = np.random.randint(0, 10, (3, 4))  # 0-9 的随机整数
empty - 未初始化数组
# 创建未初始化的数组(速度快,但值不确定)
empty_arr = np.empty((3, 4))

特殊数组创建

# 对角矩阵
diag_arr = np.diag([1, 2, 3, 4])

# 从现有数组创建副本
arr = np.array([1, 2, 3])
arr_copy = np.copy(arr)

# 创建与现有数组相同形状的新数组
original = np.array([[1, 2], [3, 4]])
zeros_like = np.zeros_like(original)
ones_like = np.ones_like(original)

数组属性

import numpy as np

arr = np.array([[1, 2, 3, 4],
                [5, 6, 7, 8],
                [9, 10, 11, 12]])

# 维度数
print(arr.ndim)           # 2

# 形状(行数,列数)
print(arr.shape)          # (3, 4)

# 元素总数
print(arr.size)           # 12

# 数据类型
print(arr.dtype)          # int64(取决于系统)

# 每个元素的字节数
print(arr.itemsize)       # 8

# 总字节数
print(arr.nbytes)         # 96

# 数据类型名称
print(arr.dtype.name)     # 'int64'

数据类型

NumPy 支持多种数据类型:

类型说明示例
int8, int16, int32, int64有符号整数np.int32
uint8, uint16, uint32, uint64无符号整数np.uint8
float16, float32, float64浮点数np.float64
complex64, complex128复数np.complex128
bool布尔值np.bool_
str_字符串np.str_
objectPython 对象np.object_
# 数据类型转换
arr_int = np.array([1, 2, 3], dtype=np.int32)
arr_float = arr_int.astype(np.float64)
arr_bool = np.array([True, False, True])

# 查看数据类型信息
print(np.finfo(np.float64))  # 浮点数信息
print(np.iinfo(np.int32))    # 整数信息

数组索引和切片

一维数组索引

import numpy as np

arr = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])

# 正向索引(从 0 开始)
print(arr[0])       # 10
print(arr[5])       # 60

# 负向索引(从 -1 开始)
print(arr[-1])      # 100
print(arr[-3])      # 80

# 修改元素
arr[0] = 999
print(arr[0])       # 999

一维数组切片

arr = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])

# 基本切片 [start:stop:step]
print(arr[2:5])         # [30 40 50]
print(arr[:5])          # [10 20 30 40 50]
print(arr[5:])          # [60 70 80 90 100]
print(arr[::2])         # [10 30 50 70 90]
print(arr[1::2])        # [20 40 60 80 100]
print(arr[::-1])        # [100 90 80 70 60 50 40 30 20 10](反转)

# 注意:切片返回的是视图,不是副本
slice_arr = arr[2:5]
slice_arr[0] = 999
print(arr)  # 原数组也被修改!

二维数组索引

arr_2d = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])

# 访问单个元素
print(arr_2d[0, 0])     # 1(第0行,第0列)
print(arr_2d[1, 2])     # 7(第1行,第2列)
print(arr_2d[2, -1])    # 12(最后一列)

# 访问整行
print(arr_2d[0])        # [1 2 3 4]
print(arr_2d[1])        # [5 6 7 8]

# 访问整列
print(arr_2d[:, 0])     # [1 5 9]
print(arr_2d[:, 2])     # [3 7 11]

二维数组切片

arr_2d = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])

# 切片语法 [row_start:row_stop, col_start:col_stop]
print(arr_2d[0:2, 1:3])     # [[2 3]
                             #  [6 7]]

print(arr_2d[:2, :2])       # [[1 2]
                             #  [5 6]]

print(arr_2d[1:, 2:])       # [[ 7  8]
                             #  [11 12]]

# 步长切片
print(arr_2d[::2, ::2])     # [[ 1  3]
                             #  [ 9 11]]

花式索引(Fancy Indexing)

arr = np.array([10, 20, 30, 40, 50, 60, 70, 80])

# 使用索引数组
indices = [0, 3, 5, 7]
print(arr[indices])         # [10 40 60 80]

# 使用布尔索引
mask = arr > 40
print(mask)                 # [False False False False  True  True  True  True]
print(arr[mask])            # [50 60 70 80]

# 组合条件
print(arr[(arr > 30) & (arr < 70)])   # [40 50 60]
print(arr[(arr < 20) | (arr > 70)])   # [10 80]

# 二维数组的花式索引
arr_2d = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

rows = [0, 2]
cols = [1, 2]
print(arr_2d[rows, cols])   # [2 9]

np.where 函数

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

# 找到满足条件的索引
indices = np.where(arr > 5)
print(indices)              # (array([5, 6, 7, 8, 9]),)
print(arr[indices])         # [ 6  7  8  9 10]

# 条件赋值
result = np.where(arr > 5, 'big', 'small')
print(result)               # ['small' 'small' 'small' 'small' 'small' 'big' 'big' 'big' 'big' 'big']

数组操作

数组复制

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

# 视图(共享数据)
view_arr = arr.view()
view_arr[0] = 999
print(arr)          # [999   2   3   4   5](原数组被修改)

# 副本(独立数据)
copy_arr = arr.copy()
copy_arr[0] = 888
print(arr)          # [999   2   3   4   5](原数组不变)
print(copy_arr)     # [888   2   3   4   5]

数组拼接

arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

# 水平拼接
h_stack = np.hstack((arr1, arr2))
print(h_stack)          # [1 2 3 4 5 6]

# 垂直拼接(需要二维)
arr1_2d = np.array([[1, 2, 3]])
arr2_2d = np.array([[4, 5, 6]])
v_stack = np.vstack((arr1_2d, arr2_2d))
print(v_stack)          # [[1 2 3]
                        #  [4 5 6]]

# 通用拼接
concat_h = np.concatenate((arr1, arr2), axis=0)
concat_v = np.concatenate((arr1_2d, arr2_2d), axis=0)

数组分割

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

# 等分
split_arr = np.split(arr, 3)
print(split_arr)        # [array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]

# 在指定位置分割
split_arr = np.split(arr, [3, 6])
print(split_arr)        # [array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]

# 水平和垂直分割(二维数组)
arr_2d = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])

h_split = np.hsplit(arr_2d, 2)
v_split = np.vsplit(arr_2d, 3)

数组排序

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

# 排序(返回新数组)
sorted_arr = np.sort(arr)
print(sorted_arr)       # [1 1 2 3 3 4 5 5 6 9]

# 原地排序
arr.sort()
print(arr)              # [1 1 2 3 3 4 5 5 6 9]

# 降序排序
desc_arr = np.sort(arr)[::-1]
print(desc_arr)         # [9 6 5 5 4 3 3 2 1 1]

# 获取排序索引
indices = np.argsort(arr)
print(indices)          # [1 3 6 0 7 2 4 8 9 5]

去重

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

# 去重
unique_arr = np.unique(arr)
print(unique_arr)       # [1 2 3 4 5]

# 返回计数
unique_vals, counts = np.unique(arr, return_counts=True)
print(unique_vals)      # [1 2 3 4 5]
print(counts)           # [1 2 3 2 1]

数学运算

基本算术运算

import numpy as np

a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])

# 加法
print(a + b)            # [11 22 33 44 55]
print(np.add(a, b))     # [11 22 33 44 55]

# 减法
print(b - a)            # [ 9 18 27 36 45]
print(np.subtract(b, a))

# 乘法(元素级)
print(a * b)            # [ 10  40  90 160 250]
print(np.multiply(a, b))

# 除法
print(b / a)            # [10. 10. 10. 10. 10.]
print(np.divide(b, a))

# 幂运算
print(a ** 2)           # [ 1  4  9 16 25]
print(np.power(a, 2))

# 取模
print(b % a)            # [0 0 0 0 0]
print(np.mod(b, a))

标量运算

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

print(arr + 10)         # [11 12 13 14 15]
print(arr * 2)          # [ 2  4  6  8 10]
print(arr ** 2)         # [ 1  4  9 16 25]
print(arr / 2)          # [0.5 1.  1.5 2.  2.5]

矩阵乘法

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

# 矩阵乘法
result = np.dot(A, B)
print(result)           # [[19 22]
                        #  [43 50]]

# 或使用 @ 运算符(Python 3.5+)
result = A @ B

# 或使用 matmul
result = np.matmul(A, B)

比较运算

a = np.array([1, 2, 3, 4, 5])
b = np.array([5, 4, 3, 2, 1])

print(a > b)            # [False False  True  True  True]
print(a == b)           # [False False  True False False]
print(a >= 3)           # [False False  True  True  True]
print(a != b)           # [ True  True False  True  True]

逻辑运算

a = np.array([True, False, True, False])
b = np.array([True, True, False, False])

print(np.logical_and(a, b))   # [ True False False False]
print(np.logical_or(a, b))    # [ True  True  True False]
print(np.logical_not(a))      # [False  True False  True]
print(np.logical_xor(a, b))   # [False  True  True False]

三角函数

angles = np.array([0, np.pi/6, np.pi/4, np.pi/3, np.pi/2])

print(np.sin(angles))     # 正弦
print(np.cos(angles))     # 余弦
print(np.tan(angles))     # 正切

# 反三角函数
print(np.arcsin(1))       # π/2
print(np.arccos(0))       # π/2
print(np.arctan(1))       # π/4

指数和对数

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

# 指数
print(np.exp(arr))        # e^x
print(np.exp2(arr))       # 2^x
print(np.power(2, arr))   # 2^x

# 对数
print(np.log(arr))        # 自然对数 ln(x)
print(np.log2(arr))       # log2(x)
print(np.log10(arr))      # log10(x)

舍入函数

arr = np.array([1.2, 2.5, 3.7, -1.2, -2.5, -3.7])

print(np.round(arr))      # 四舍五入 [ 1.  2.  4. -1. -2. -4.]
print(np.floor(arr))      # 向下取整 [ 1.  2.  3. -2. -3. -4.]
print(np.ceil(arr))       # 向上取整 [ 2.  3.  4. -1. -2. -3.]
print(np.trunc(arr))      # 截断小数 [ 1.  2.  3. -1. -2. -3.]

统计函数

import numpy as np

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

基本统计

# 求和
print(np.sum(arr))            # 55
print(np.sum(arr_2d))         # 45
print(np.sum(arr_2d, axis=0)) # [12 15 18](按列求和)
print(np.sum(arr_2d, axis=1)) # [ 6 15 24](按行求和)

# 平均值
print(np.mean(arr))           # 5.5
print(np.mean(arr_2d, axis=0))

# 中位数
print(np.median(arr))         # 5.5

# 最大值和最小值
print(np.max(arr))            # 10
print(np.min(arr))            # 1
print(np.argmax(arr))         # 9(最大值的索引)
print(np.argmin(arr))         # 0(最小值的索引)

# 极差
print(np.ptp(arr))            # 9(max - min)

方差和标准差

# 方差
print(np.var(arr))            # 方差

# 标准差
print(np.std(arr))            # 标准差

# 样本方差和标准差(ddof=1)
print(np.var(arr, ddof=1))
print(np.std(arr, ddof=1))

百分位数

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

print(np.percentile(arr, 50))   # 50% 分位数(中位数)
print(np.percentile(arr, 25))   # 25% 分位数
print(np.percentile(arr, 75))   # 75% 分位数
print(np.percentile(arr, [25, 50, 75]))  # 多个分位数

累积运算

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

# 累积和
print(np.cumsum(arr))         # [ 1  3  6 10 15]

# 累积积
print(np.cumprod(arr))        # [  1   2   6  24 120]

# 累积最大值
print(np.maximum.accumulate(arr))  # [1 2 3 4 5]

# 累积最小值
print(np.minimum.accumulate(arr))  # [1 2 3 4 5]

相关性

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

# 相关系数矩阵
corr_matrix = np.corrcoef(x, y)
print(corr_matrix)

# 协方差矩阵
cov_matrix = np.cov(x, y)
print(cov_matrix)

数组形状操作

重塑(Reshape)

import numpy as np

arr = np.arange(12)  # [0 1 2 3 4 5 6 7 8 9 10 11]

# 重塑为 3x4 矩阵
reshaped = arr.reshape(3, 4)
print(reshaped)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 重塑为 2x6 矩阵
reshaped2 = arr.reshape(2, 6)

# 自动推断维度(使用 -1)
reshaped3 = arr.reshape(3, -1)  # 自动计算第二维为 4
reshaped4 = arr.reshape(-1, 4)  # 自动计算第一维为 3

# 展平
flattened = reshaped.flatten()  # 返回副本
raveled = reshaped.ravel()      # 返回视图(更快)

转置

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

# 转置
transposed = arr_2d.T
print(transposed)
# [[1 4]
#  [2 5]
#  [3 6]]

# 或使用 transpose
transposed2 = np.transpose(arr_2d)

# 高维数组的轴交换
arr_3d = np.random.rand(2, 3, 4)
swapped = np.transpose(arr_3d, (2, 0, 1))  # 交换轴

增加/减少维度

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

# 增加维度
arr_2d = arr[np.newaxis, :]     # 形状: (1, 5)
arr_2d_v = arr[:, np.newaxis]   # 形状: (5, 1)

# 或使用 reshape
arr_2d = arr.reshape(1, -1)
arr_2d_v = arr.reshape(-1, 1)

# 或使用 expand_dims
arr_2d = np.expand_dims(arr, axis=0)
arr_2d_v = np.expand_dims(arr, axis=1)

# 减少维度
arr_squeezed = np.squeeze(arr_2d)  # 移除大小为 1 的维度

堆叠

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

# 垂直堆叠
v_stack = np.vstack((a, b))
print(v_stack)
# [[1 2 3]
#  [4 5 6]]

# 水平堆叠
h_stack = np.hstack((a, b))
print(h_stack)  # [1 2 3 4 5 6]

# 深度堆叠(3维)
d_stack = np.dstack((a, b))

# 通用堆叠
stack_v = np.stack((a, b), axis=0)
stack_h = np.stack((a, b), axis=1)

线性代数

NumPy 提供了强大的线性代数功能(np.linalg 模块)。

import numpy as np

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

矩阵运算

# 矩阵乘法
C = np.dot(A, B)
C = A @ B
C = np.matmul(A, B)

# 矩阵幂
A_squared = np.linalg.matrix_power(A, 2)

# 转置
A_T = A.T

行列式和逆矩阵

# 行列式
det_A = np.linalg.det(A)
print(det_A)  # -2.0

# 逆矩阵
if det_A != 0:
    A_inv = np.linalg.inv(A)
    print(A_inv)

    # 验证:A * A_inv = I
    identity = A @ A_inv
    print(np.round(identity))  # [[1. 0.]
                               #  [0. 1.]]

特征值和特征向量

# 特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)

解线性方程组

# 解 Ax = b
A = np.array([[2, 1],
              [1, 3]])
b = np.array([8, 13])

x = np.linalg.solve(A, b)
print(x)  # [1. 6.]

# 验证
print(A @ x)  # [ 8. 13.]

其他线性代数函数

# 秩
rank = np.linalg.matrix_rank(A)

# 迹(对角线元素之和)
trace = np.trace(A)

# 范数
norm = np.linalg.norm(A)
norm_fro = np.linalg.norm(A, 'fro')  # Frobenius 范数

# QR 分解
Q, R = np.linalg.qr(A)

# SVD 分解
U, S, Vt = np.linalg.svd(A)

# Cholesky 分解(对称正定矩阵)
A_sym = np.array([[4, 2],
                  [2, 3]])
L = np.linalg.cholesky(A_sym)

随机数生成

NumPy 的 random 模块提供了丰富的随机数生成功能。

新版 API(推荐)

import numpy as np

# 创建随机数生成器
rng = np.random.default_rng(seed=42)

# 均匀分布 [0, 1)
random_uniform = rng.random(5)
print(random_uniform)

# 指定范围的均匀分布
random_range = rng.uniform(0, 10, 5)
print(random_range)

# 标准正态分布
random_normal = rng.standard_normal(5)
print(random_normal)

# 指定均值和标准差的正态分布
random_norm = rng.normal(loc=0, scale=1, size=5)
print(random_norm)

# 随机整数
random_int = rng.integers(0, 10, 5)
print(random_int)

# 从数组中随机选择
choices = rng.choice([1, 2, 3, 4, 5], 3, replace=False)
print(choices)

# 洗牌
arr = np.array([1, 2, 3, 4, 5])
rng.shuffle(arr)
print(arr)

旧版 API(仍可使用)

# 均匀分布
np.random.rand(3, 4)              # [0, 1) 均匀分布
np.random.random((3, 4))

# 标准正态分布
np.random.randn(3, 4)

# 随机整数
np.random.randint(0, 10, (3, 4))

# 设置种子
np.random.seed(42)

常用分布

rng = np.random.default_rng()

# 二项分布
binomial = rng.binomial(n=10, p=0.5, size=1000)

# 泊松分布
poisson = rng.poisson(lam=5, size=1000)

# 指数分布
exponential = rng.exponential(scale=2.0, size=1000)

# 伽马分布
gamma = rng.gamma(shape=2.0, scale=2.0, size=1000)

# Beta 分布
beta = rng.beta(a=2, b=5, size=1000)

广播机制

广播(Broadcasting)是 NumPy 最强大的特性之一,允许不同形状的数组进行算术运算。

广播规则

  1. 如果数组维度数不同,较小的数组在前面补 1
  2. 如果某个维度大小不同,且其中一个为 1,则该维度可以扩展
  3. 如果维度大小不同且都不为 1,则报错

示例

import numpy as np

# 示例 1:标量与数组
arr = np.array([1, 2, 3, 4, 5])
result = arr + 10
print(result)  # [11 12 13 14 15]

# 示例 2:一维数组与二维数组
arr_2d = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])
arr_1d = np.array([10, 20, 30])

result = arr_2d + arr_1d
print(result)
# [[11 22 33]
#  [14 25 36]
#  [17 28 39]]

# 示例 3:列向量与行向量
col = np.array([[1],
                [2],
                [3]])  # 形状: (3, 1)
row = np.array([10, 20, 30])  # 形状: (3,)

result = col + row
print(result)
# [[11 21 31]
#  [12 22 32]
#  [13 23 33]]

# 示例 4:不兼容的形状(会报错)
try:
    arr1 = np.array([1, 2, 3])
    arr2 = np.array([1, 2])
    result = arr1 + arr2  # ValueError!
except ValueError as e:
    print(f"错误: {e}")

广播应用

# 标准化数据
data = np.random.randn(100, 5)
mean = np.mean(data, axis=0)
std = np.std(data, axis=0)
normalized = (data - mean) / std

# 外积
a = np.array([1, 2, 3])
b = np.array([10, 20, 30, 40])
outer = a[:, np.newaxis] * b
print(outer)
# [[ 10  20  30  40]
#  [ 20  40  60  80]
#  [ 30  60  90 120]]

性能优化

向量化运算

import numpy as np
import time

# ❌ 避免:使用循环
def slow_sum(arr):
    result = 0
    for x in arr:
        result += x ** 2
    return result

# ✅ 推荐:使用向量化
def fast_sum(arr):
    return np.sum(arr ** 2)

arr = np.random.rand(1000000)

start = time.time()
slow_sum(arr)
print(f"循环耗时: {time.time() - start:.4f}秒")

start = time.time()
fast_sum(arr)
print(f"向量化耗时: {time.time() - start:.4f}秒")

使用内置函数

# ❌ 避免
result = np.array([x * 2 for x in arr])

# ✅ 推荐
result = arr * 2

# ❌ 避免
result = np.array([np.sqrt(x) for x in arr])

# ✅ 推荐
result = np.sqrt(arr)

内存优化

# 选择合适的数据类型
arr_float64 = np.array([1, 2, 3], dtype=np.float64)  # 8 字节/元素
arr_float32 = np.array([1, 2, 3], dtype=np.float32)  # 4 字节/元素
arr_int16 = np.array([1, 2, 3], dtype=np.int16)      # 2 字节/元素

# 使用视图而非副本
view = arr[:]      # 视图,不复制数据
copy = arr.copy()  # 副本,复制数据

# 就地操作
arr += 1           # 就地加法,节省内存
arr = arr + 1      # 创建新数组

批量处理

# 处理大数据集时分批处理
def process_in_batches(data, batch_size=1000):
    results = []
    for i in range(0, len(data), batch_size):
        batch = data[i:i+batch_size]
        result = np.sum(batch ** 2)
        results.append(result)
    return np.sum(results)

实战案例

案例 1:图像处理基础

import numpy as np
import matplotlib.pyplot as plt

# 创建示例图像(100x100 像素,RGB)
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)

# 转换为灰度图
gray_image = np.mean(image, axis=2).astype(np.uint8)

# 调整亮度
brighter = np.clip(image + 50, 0, 255).astype(np.uint8)

# 翻转图像
flipped_h = np.flip(image, axis=1)  # 水平翻转
flipped_v = np.flip(image, axis=0)  # 垂直翻转

# 裁剪
cropped = image[25:75, 25:75, :]

print(f"原始图像形状: {image.shape}")
print(f"灰度图形状: {gray_image.shape}")

案例 2:数据统计分析

import numpy as np

# 生成模拟数据
np.random.seed(42)
scores = np.random.normal(loc=75, scale=10, size=1000)

# 基本统计
print(f"平均分: {np.mean(scores):.2f}")
print(f"中位数: {np.median(scores):.2f}")
print(f"标准差: {np.std(scores):.2f}")
print(f"最高分: {np.max(scores):.2f}")
print(f"最低分: {np.min(scores):.2f}")

# 分数分布
bins = np.arange(0, 101, 10)
hist, bin_edges = np.histogram(scores, bins=bins)
print("\n分数分布:")
for i in range(len(hist)):
    print(f"{bin_edges[i]:.0f}-{bin_edges[i+1]:.0f}: {hist[i]}人")

# 百分位数
print(f"\n前 10% 分数线: {np.percentile(scores, 90):.2f}")
print(f"前 25% 分数线: {np.percentile(scores, 75):.2f}")

案例 3:矩阵运算求解方程组

import numpy as np

# 三元一次方程组
# 2x + y - z = 8
# -3x - y + 2z = -11
# -2x + y + 2z = -3

A = np.array([[2, 1, -1],
              [-3, -1, 2],
              [-2, 1, 2]])

b = np.array([8, -11, -3])

# 求解
solution = np.linalg.solve(A, b)
print(f"x = {solution[0]:.2f}")
print(f"y = {solution[1]:.2f}")
print(f"z = {solution[2]:.2f}")

# 验证
print(f"\n验证: {A @ solution}")
print(f"期望: {b}")

案例 4:蒙特卡洛模拟估算 π

import numpy as np

def estimate_pi(num_samples=1000000):
    """使用蒙特卡洛方法估算 π"""
    # 在 [0,1] x [0,1] 正方形内随机生成点
    points = np.random.random((num_samples, 2))

    # 计算每个点到原点的距离
    distances = np.sqrt(points[:, 0]**2 + points[:, 1]**2)

    # 统计在单位圆内的点
    inside_circle = np.sum(distances <= 1)

    # π ≈ 4 * (圆内点数 / 总点数)
    pi_estimate = 4 * inside_circle / num_samples

    return pi_estimate

pi_est = estimate_pi(1000000)
print(f"估算的 π 值: {pi_est:.6f}")
print(f"实际 π 值: {np.pi:.6f}")
print(f"误差: {abs(pi_est - np.pi):.6f}")

案例 5:股票收益率分析

import numpy as np

# 模拟股票价格(30天)
np.random.seed(42)
days = 30
initial_price = 100
daily_returns = np.random.normal(0.001, 0.02, days)
prices = initial_price * np.cumprod(1 + daily_returns)

# 计算日收益率
returns = np.diff(prices) / prices[:-1]

# 统计分析
print(f"初始价格: ${prices[0]:.2f}")
print(f"最终价格: ${prices[-1]:.2f}")
print(f"总收益率: {(prices[-1] - prices[0]) / prices[0] * 100:.2f}%")
print(f"平均日收益率: {np.mean(returns) * 100:.4f}%")
print(f"日收益率标准差: {np.std(returns) * 100:.4f}%")
print(f"最高价格: ${np.max(prices):.2f}")
print(f"最低价格: ${np.min(prices):.2f}")

# 累计收益率
cumulative_returns = (prices - prices[0]) / prices[0] * 100
print(f"\n每日累计收益率:")
for i, ret in enumerate(cumulative_returns):
    print(f"第{i+1}天: {ret:.2f}%")

总结

核心知识点回顾

  1. 数组创建np.array(), np.zeros(), np.ones(), np.arange(), np.linspace()
  2. 数组属性.ndim, .shape, .size, .dtype
  3. 索引切片:基本索引、切片、花式索引、布尔索引
  4. 数学运算:算术运算、矩阵乘法、三角函数、指数对数
  5. 统计函数sum(), mean(), std(), max(), min()
  6. 形状操作reshape(), transpose(), flatten(), stack()
  7. 线性代数linalg 模块的各种矩阵运算
  8. 随机数random 模块生成各种分布的随机数
  9. 广播机制:不同形状数组的自动对齐运算

学习建议

  • 多练习:通过实际项目巩固知识
  • 理解广播:广播是 NumPy 的核心,务必深入理解
  • 向量化思维:避免使用循环,充分利用向量化运算
  • 查阅文档:NumPy 官方文档非常详细,善用搜索
  • 结合应用:与 Pandas、Matplotlib 结合使用

下一步

掌握 NumPy 后,建议继续学习:

  • Pandas:数据处理和分析
  • Matplotlib:数据可视化
  • SciPy:科学计算
  • Scikit-learn:机器学习

参考资料