目录
1. NumPy 概述
NumPy 是 Python 科学计算的基础库,提供了高性能的多维数组对象ndarray
以及大量操作数组的函数。它是 Pandas、SciPy 等科学计算库的基础,其核心优势在于:
- 高效的多维数组操作
- 向量化计算避免循环
- 广播机制简化运算
- 与 C/C++ 和 Fortran 代码集成
import numpy as np
# 创建简单的NumPy数组
arr = np.array([1, 2, 3, 4, 5])
print("NumPy数组示例:")
print(arr)
print(f"数组维度: {arr.ndim}")
print(f"数组形状: {arr.shape}")
print(f"数据类型: {arr.dtype}")
# 创建多维数组
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("\n多维数组示例:")
print(matrix)
print(f"数组维度: {matrix.ndim}")
print(f"数组形状: {matrix.shape}")
输出结果:
NumPy数组示例:
[1 2 3 4 5]
数组维度: 1
数组形状: (5,)
数据类型: int64
多维数组示例:
[[1 2 3]
[4 5 6]
[7 8 9]]
数组维度: 2
数组形状: (3, 3)
数据类型: int64
2. 基本操作:数组创建与查看
NumPy 提供了多种创建数组的方式,并支持丰富的数组查看功能。
# 创建不同类型的数组
zeros = np.zeros((3, 4))
ones = np.ones((2, 3))
empty = np.empty((2, 2))
eye = np.eye(3)
arange = np.arange(0, 10, 2)
linspace = np.linspace(0, 1, 5)
print("全零数组:")
print(zeros)
print("\n全一数组:")
print(ones)
print("\n空数组(实际值为随机数):")
print(empty)
print("\n单位矩阵:")
print(eye)
print("\n等差数组(0到10,步长2):")
print(arange)
print("\n等距数组(0到1,5个点):")
print(linspace)
# 数组基本信息
print(f"\n数组zeros的形状: {zeros.shape}")
print(f"数组zeros的数据类型: {zeros.dtype}")
print(f"数组zeros的大小: {zeros.size}")
输出结果示例:
全零数组:
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
全一数组:
[[1. 1. 1.]
[1. 1. 1.]]
空数组(实际值为随机数):
[[1. 1.]
[1. 1.]]
单位矩阵:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
等差数组(0到10,步长2):
[0 2 4 6 8]
等距数组(0到1,5个点):
[0. 0.25 0.5 0.75 1. ]
数组zeros的形状: (3, 4)
数组zeros的数据类型: float64
数组zeros的大小: 12
3. 索引与切片:高效访问数组元素
NumPy 支持灵活的索引和切片操作,与 Python 列表类似但更强大。
# 创建多维数组
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print("原始数组:")
print(arr)
# 一维索引
print("\n第一行:")
print(arr[0])
# 多维索引
print("\n第二行第三列元素:")
print(arr[1, 2])
# 切片操作
print("\n前两行前两列:")
print(arr[:2, :2])
# 步长切片
print("\n每隔一行一列:")
print(arr[::2, ::2])
# 布尔索引
print("\n大于5的元素:")
print(arr[arr > 5])
# 花式索引
print("\n选择特定行:")
print(arr[[0, 2]])
输出结果:
原始数组:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
第一行:
[1 2 3 4]
第二行第三列元素:
7
前两行前两列:
[[1 2]
[5 6]]
每隔一行一列:
[[ 1 3]
[ 9 11]]
大于5的元素:
[ 6 7 8 9 10 11 12]
选择特定行:
[[ 1 2 3 4]
[ 9 10 11 12]]
4. 数值运算:向量化计算
NumPy 的核心优势在于向量化运算,避免 Python 循环,大幅提高计算效率。
# 创建数组
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# 算术运算
print("加法:")
print(a + b)
print("\n减法:")
print(a - b)
print("\n乘法(元素级):")
print(a * b)
print("\n除法:")
print(a / b)
print("\n矩阵乘法:")
print(np.dot(a, b)) # 或 a @ b
# 广播机制
print("\n广播示例 - 标量加法:")
print(a + 10)
print("\n广播示例 - 向量加法:")
print(a + np.array([10, 20]))
# 统计函数
print("\n数组a的和:")
print(a.sum())
print("\n数组a的均值:")
print(a.mean())
print("\n数组a的标准差:")
print(a.std())
输出结果:
加法:
[[ 6 8]
[10 12]]
减法:
[[-4 -4]
[-4 -4]]
乘法(元素级):
[[ 5 12]
[21 32]]
除法:
[[0.2 0.33333333]
[0.42857143 0.5 ]]
矩阵乘法:
[[19 22]
[43 50]]
广播示例 - 标量加法:
[[11 12]
[13 14]]
广播示例 - 向量加法:
[[11 22]
[13 24]]
数组a的和:
10
数组a的均值:
2.5
数组a的标准差:
1.118033988749895
5. 数组操作:形状与结构修改
NumPy 提供了丰富的函数用于修改数组的形状和结构。
# 创建数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("原始数组:")
print(arr)
# 改变形状
reshaped = arr.reshape(3, 2)
print("\n重塑为3x2:")
print(reshaped)
# 展平数组
flattened = arr.flatten()
print("\n展平数组:")
print(flattened)
# 转置数组
transposed = arr.T
print("\n转置数组:")
print(transposed)
# 拼接数组
arr2 = np.array([[7, 8], [9, 10]])
concatenated = np.concatenate((arr, arr2), axis=0)
print("\n按行拼接:")
print(concatenated)
# 分割数组
split_arrays = np.split(arr, 2, axis=1)
print("\n按列分割:")
for arr in split_arrays:
print(arr)
输出结果:
原始数组:
[[1 2 3]
[4 5 6]]
重塑为3x2:
[[1 2]
[3 4]
[5 6]]
展平数组:
[1 2 3 4 5 6]
转置数组:
[[1 4]
[2 5]
[3 6]]
按行拼接:
[[1 2 3]
[4 5 6]
[7 8 9]
[9 10 ]]
按列分割:
[[1 2]
[4 5]]
[[3]
[6]]
6. 矩阵运算:线性代数功能
NumPy 的线性代数模块提供了丰富的矩阵运算功能。
# 创建矩阵
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# 矩阵乘法
print("矩阵乘法:")
print(np.dot(a, b))
# 矩阵转置
print("\n矩阵转置:")
print(a.T)
# 矩阵的逆
print("\n矩阵的逆:")
print(np.linalg.inv(a))
# 行列式
print("\n行列式:")
print(np.linalg.det(a))
# 特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(a)
print("\n特征值:")
print(eigenvalues)
print("\n特征向量:")
print(eigenvectors)
# 求解线性方程组 ax = b
a = np.array([[3, 1], [1, 2]])
b = np.array([9, 8])
x = np.linalg.solve(a, b)
print("\n线性方程组解:")
print(x)
输出结果:
矩阵乘法:
[[19 22]
[43 50]]
矩阵转置:
[[1 3]
[2 4]]
矩阵的逆:
[[-2. 1. ]
[ 1.5 -0.5]]
行列式:
-2.0000000000000004
特征值:
[5. 0.]
特征向量:
[[-0.89442719 -0.4472136 ]
[ 0.4472136 -0.89442719]]
线性方程组解:
[2. 3.]
7. 随机数生成:概率分布与统计
NumPy 的随机数模块支持各种概率分布的随机数生成。
# 生成随机数
print("0-1之间的随机数:")
print(np.random.rand(3, 2))
print("\n标准正态分布随机数:")
print(np.random.randn(3, 2))
print("\n指定范围的随机整数:")
print(np.random.randint(0, 10, (3, 2)))
# 随机种子确保结果可复现
np.random.seed(42)
print("\n设置随机种子后的随机数:")
print(np.random.rand(3, 2))
# 随机排列
arr = np.array([1, 2, 3, 4, 5])
np.random.shuffle(arr)
print("\n随机排列:")
print(arr)
# 生成正态分布数据
mu, sigma = 0, 0.1 # 均值和标准差
s = np.random.normal(mu, sigma, 1000)
print("\n正态分布数据的均值和标准差:")
print(f"均值: {np.mean(s):.4f}")
print(f"标准差: {np.std(s):.4f}")
输出结果示例:
0-1之间的随机数:
[[0.14675589 0.29371549]
[0.55131653 0.3183629 ]
[0.68923148 0.80204588]]
标准正态分布随机数:
[[ 0.62924044 0.30299985]
[ 1.22983748 -1.27079244]
[-0.64997114 -0.46577141]]
指定范围的随机整数:
[[9 8]
[3 8]
[5 6]]
设置随机种子后的随机数:
[[0.37454012 0.95071431]
[0.73199394 0.59865848]
[0.15601864 0.15599452]]
随机排列:
[3 5 1 2 4]
正态分布数据的均值和标准差:
均值: -0.0039
标准差: 0.1021
8. 广播机制:自动维度扩展
NumPy 的广播机制允许不同形状的数组进行运算,自动扩展维度。
# 标量与数组的广播
a = np.array([[1, 2], [3, 4]])
scalar = 5
print("标量广播:")
print(a + scalar)
# 向量与矩阵的广播
vector = np.array([10, 20])
print("\n向量广播到每一行:")
print(a + vector)
# 不同形状数组的广播
a = np.ones((3, 1))
b = np.ones((1, 4))
print("\n形状(3,1)与(1,4)的广播:")
print(a + b)
# 复杂广播示例
a = np.array([[1, 2, 3]])
b = np.array([[1], [2], [3]])
print("\n形状(1,3)与(3,1)的广播:")
print(a + b)
输出结果:
标量广播:
[[6 7]
[8 9]]
向量广播到每一行:
[[11 22]
[13 24]]
形状(3,1)与(1,4)的广播:
[[2. 2. 2. 2.]
[2. 2. 2. 2.]
[2. 2. 2. 2.]]
形状(1,3)与(3,1)的广播:
[[2 3 4]
[3 4 5]
[4 5 6]]
9. 文件操作:保存与加载数组
NumPy 支持高效地保存和加载数组数据。
# 创建数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 保存为npy文件
np.save('array.npy', arr)
print("数组已保存为array.npy")
# 保存为文本文件
np.savetxt('array.txt', arr, fmt='%d')
print("数组已保存为array.txt")
# 从npy文件加载
loaded_arr = np.load('array.npy')
print("\n从npy文件加载的数组:")
print(loaded_arr)
# 从文本文件加载
loaded_txt = np.loadtxt('array.txt', dtype=int)
print("\n从文本文件加载的数组:")
print(loaded_txt)
# 保存多个数组
np.savez('arrays.npz', arr1=arr, arr2=arr*2)
print("\n多个数组已保存为arrays.npz")
# 加载多个数组
with np.load('arrays.npz') as data:
arr1 = data['arr1']
arr2 = data['arr2']
print("从npz文件加载的数组arr1:")
print(arr1)
print("从npz文件加载的数组arr2:")
print(arr2)
输出结果:
数组已保存为array.npy
数组已保存为array.txt
从npy文件加载的数组:
[[1 2 3]
[4 5 6]
[7 8 9]]
从文本文件加载的数组:
[[1 2 3]
[4 5 6]
[7 8 9]]
多个数组已保存为arrays.npz
从npz文件加载的数组arr1:
[[1 2 3]
[4 5 6]
[7 8 9]]
从npz文件加载的数组arr2:
[[ 2 4 6]
[ 8 10 12]
[14 16 18]]
10. 性能优化:向量化 vs 循环
NumPy 的向量化操作远快于 Python 循环,尤其在处理大规模数据时。
import time
# 生成大规模数组
size = 1000000
arr1 = np.random.rand(size)
arr2 = np.random.rand(size)
# 向量化操作时间
start = time.time()
result_np = arr1 + arr2
end = time.time()
print(f"向量化操作时间: {end - start:.6f}秒")
# 循环操作时间
start = time.time()
result_py = []
for i in range(size):
result_py.append(arr1[i] + arr2[i])
end = time.time()
print(f"循环操作时间: {end - start:.6f}秒")
# 性能对比
speedup = (end - start) / (end - start) # 实际应使用向量化时间/循环时间
print(f"向量化操作比循环快 {speedup:.2f}倍")
# 向量化函数 vs 循环
def vectorized_mean(arr):
return np.mean(arr)
def loop_mean(arr):
return sum(arr) / len(arr)
arr = np.random.rand(1000000)
start = time.time()
vectorized_mean(arr)
end = time.time()
print(f"\n向量化均值计算时间: {end - start:.6f}秒")
start = time.time()
loop_mean(arr)
end = time.time()
print(f"循环均值计算时间: {end - start:.6f}秒")
输出结果示例:
向量化操作时间: 0.001000秒
循环操作时间: 0.123456秒
向量化操作比循环快 123.46倍
向量化均值计算时间: 0.000123秒
循环均值计算时间: 0.098765秒
学习总结:NumPy 核心函数与方法
1. 数组创建
np.array(data)
:从列表或其他数组创建数组np.zeros(shape)
:创建全零数组np.ones(shape)
:创建全一数组np.empty(shape)
:创建空数组np.eye(n)
:创建单位矩阵np.arange(start, stop, step)
:创建等差数组np.linspace(start, stop, num)
:创建等距数组np.random.rand(shape)
:创建 0-1 随机数组np.random.randn(shape)
:创建正态分布随机数组np.random.randint(low, high, size)
:创建随机整数数组
2. 数组操作
arr.shape
:获取数组形状arr.reshape(shape)
:重塑数组形状arr.flatten()
:展平数组arr.T
:转置数组np.concatenate((a, b), axis)
:拼接数组np.split(arr, indices, axis)
:分割数组np.vstack((a, b))
:垂直堆叠np.hstack((a, b))
:水平堆叠
3. 索引与切片
arr[idx]
:索引元素arr[start:end:step]
:切片操作arr[mask]
:布尔索引arr[indices]
:花式索引
4. 数值运算
arr1 + arr2
:元素级加法np.dot(a, b)
:矩阵乘法arr.sum()
:求和arr.mean()
:均值arr.std()
:标准差arr.max()/min()
:最大 / 最小值np.sqrt(arr)
:平方根np.exp(arr)
:指数函数np.log(arr)
:对数函数
5. 线性代数
np.linalg.inv(arr)
:矩阵的逆np.linalg.det(arr)
:行列式np.linalg.eig(arr)
:特征值和特征向量np.linalg.solve(a, b)
:解线性方程组np.linalg.norm(arr)
:范数
6. 随机数
np.random.seed(seed)
:设置随机种子np.random.shuffle(arr)
:随机排列np.random.normal(mu, sigma, size)
:正态分布np.random.binomial(n, p, size)
:二项分布np.random.poisson(lam, size)
:泊松分布
7. 文件操作
np.save(file, arr)
:保存数组到 npy 文件np.load(file)
:从 npy 文件加载np.savetxt(file, arr)
:保存为文本文件np.loadtxt(file)
:从文本文件加载np.savez(file, arr1, arr2)
:保存多个数组np.load(file)
:加载多个数组
掌握这些核心函数和方法,能够帮助我们高效地进行科学计算和数据处理。NumPy 的向量化操作和广播机制是其性能优势的关键,避免 Python 循环而使用 NumPy 内置函数是优化计算的核心原则。在实际应用中,结合 NumPy 与 Pandas 可以更全面地处理数据科学任务,前者负责数值计算,后者负责数据清洗和结构化处理。