第二章:NumPy进阶与数据处理
2.1 数组高级操作
形状变换与转置
arr = np.arange(9).reshape(3,3) # 创建3x3数组
print(arr.T) # 转置
print(arr.reshape(9,)) # 展平为一维(视图)
print(arr.resize(2,5)) # 强制修改形状(可能填充0)
数组合并与分割
a = np.array([[1,2],[3,4]])
b = np.array([[5,6]])
# 合并操作
print(np.vstack((a,b))) # 垂直合并 [[1,2],[3,4],[5,6]]
print(np.hstack((a,a))) # 水平合并 [[1,2,1,2],[3,4,3,4]]
print(np.concatenate([a,a], axis=0)) # 沿指定轴合并
# 分割操作
arr = np.arange(10)
print(np.split(arr, [3,5])) # 在索引3和5处分割为3个子数组
2.2 广播机制
广播规则
当数组形状不同时,NumPy会自动进行广播:
- 从最后一个维度开始对齐
- 维度大小为1的轴会自动扩展
- 缺失的维度视为1
广播示例
a = np.array([[1],[2],[3]]) # 形状(3,1)
b = np.array([4,5,6]) # 形状(3,)
print(a + b) # 广播后:[[5,6,7], [6,7,8], [7,8,9]]
2.3 高级索引
布尔索引
data = np.array([3, -1, 2, -5, 0])
mask = data > 0
print(data[mask]) # [3 2](筛选正数)
花式索引
arr = np.arange(25).reshape(5,5)
print(arr[[0,2,4], 1:3]) # 选择第0、2、4行的1-2列
2.4 通用函数(ufunc)
常用数学函数
arr = np.array([1.2, 4.5, 9.3])
print(np.floor(arr)) # 向下取整 [1. 4. 9.]
print(np.ceil(arr)) # 向上取整 [2. 5. 10.]
print(np.log(arr)) # 自然对数
print(np.power(arr, 2)) # 平方
向量化操作
# 替代循环的向量化计算
def my_func(x):
return x**2 + 2*x + 1
vectorized_func = np.vectorize(my_func)
print(vectorized_func(np.array([1,2,3])))
2.5 数据处理技巧
处理缺失值
arr = np.array([1, np.nan, 3, np.nan, 5])
print(np.isnan(arr)) # [False True False True False]
print(np.nanmean(arr)) # 忽略NaN计算均值:3.0
统计计算
data = np.random.randn(100) # 100个正态分布随机数
print(np.percentile(data, 90)) # 90%分位数
print(np.unique(data.round(1))) # 保留一位小数后的唯一值
print(np.sort(data)) # 排序数组
2.6 输入输出
二进制文件
arr = np.arange(10)
np.save("data.npy", arr) # 保存为二进制文件
loaded_arr = np.load("data.npy")
文本文件
# 保存为CSV
np.savetxt("matrix.csv", np.random.rand(5,5), delimiter=",")
# 从CSV加载
data = np.genfromtxt("data.csv", delimiter=",")
2.7 性能优化
视图 vs 拷贝
a = np.array([[1,2],[3,4]])
b = a[:2, 1] # 视图(共享内存)
c = a.copy() # 完整拷贝(独立内存)
向量化优于循环
# 低效的循环
result = np.empty(1000000)
for i in range(1000000):
result[i] = i**2
# 高效的向量化
result = np.arange(1000000)**2 # 快100倍以上
2.8 实际应用示例
数据标准化
data = np.random.randint(0,100,(10,3))
mean = data.mean(axis=0)
std = data.std(axis=0)
normalized = (data - mean)/std # Z-score标准化
随机漫步模拟
steps = 1000
random_steps = np.random.choice([-1,1], size=steps)
walk = random_steps.cumsum() # 累计路径
关键要点总结:
- 广播机制是理解数组运算的核心
- 高级索引实现复杂数据筛选
- 向量化操作大幅提升计算效率
- 掌握数据处理技巧是实际应用的基础
练习建议:
- 实现两个形状不同的数组的广播运算
- 使用布尔索引筛选出数组中大于平均值的元素
- 对随机生成的数据进行归一化处理
- 比较循环与向量化操作的时间效率差异
扩展阅读方向:
- 内存布局(C顺序 vs F顺序)
- 结构化数组与记录数组
- 与C语言的交互(ctypes模块)
- 并行计算(结合Numba加速)