摘要:在深入中级实战之前,我们先简单回顾下NumPy的基础。NumPy的核心是ndarray多维数组对象,它能高效存储和处理大量同类型数据。创建数组的方式多样,比如从Python列表创建:
在深入中级实战之前,我们先简单回顾下NumPy的基础。NumPy的核心是ndarray多维数组对象,它能高效存储和处理大量同类型数据。创建数组的方式多样,比如从Python列表创建:
import numpy as np
arr1 = np.array([1, 2, 3]) # 创建一维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]]) # 创建二维数组
也可以使用特殊函数创建数组,像np.zeros创建全0数组 ,np.ones创建全1数组,np.arange创建等差数组:
zeros_arr = np.zeros((2, 3)) # 2行3列全0数组
ones_arr = np.ones((3, 2)) # 3行2列全1数组
arange_arr = np.arange(0, 10, 2) # 从0到10(不包含10),步长为2的等差数组
1. 高级索引技巧
整数数组索引:可用于选取数组中任意位置的元素。比如有一个二维数组,想选取特定行和列交叉位置的元素:
arr = np.arange(12).reshape(3, 4)
rows = np.array([0, 1, 2])
cols = np.array([2, 3, 0])
result = arr[rows, cols]
print(result) # 输出 [ 2 7 10]
• 布尔索引进阶:布尔索引不仅能筛选元素,还能用于修改数组。比如将数组中大于某个值的元素全部替换:
arr = np.random.randint(1, 10, (4, 4))
mask = arr > 5
arr[mask] = -1
print(arr)
2. 数组拼接与分割
拼接:np.concatenate用于拼接数组,可以沿指定轴进行。一维数组拼接很简单,多维数组拼接时要注意轴的选择:
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
concatenated_1d = np.concatenate((a, b))
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
concatenated_2d_axis0 = np.concatenate((arr1, arr2), axis=0) # 沿轴0拼接,增加行数
concatenated_2d_axis1 = np.concatenate((arr1, arr2), axis=1) # 沿轴1拼接,增加列数
• 分割:np.split用于分割数组。将一个数组按照指定位置分割成多个子数组:
arr = np.arange(9)
sub_arrays = np.split(arr, [3, 6])
print(sub_arrays) # 输出 [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
1. 广播机制深入剖析
广播机制是NumPy强大之处,能让不同形状数组间进行运算。当两个数组形状不同时,NumPy会自动尝试广播使其兼容:
a = np.array([1, 2, 3])
b = np.array([[1], [2], [3]])
result = a + b
print(result)
广播规则要求数组在某一维度上要么尺寸相同,要么其中一个为1 。像(3, 1)形状数组和(1, 4)形状数组可广播相加得到(3, 4)数组:
arr1 = np.random.rand(3, 1)
arr2 = np.random.rand(1, 4)
sum_arr = arr1 + arr2
2. 通用函数(ufunc)高级用法
自定义ufunc:虽然原生ufunc性能高,但有时需要自定义。使用np.frompyfunc创建自定义ufunc,但性能不如原生,适用于简单逻辑且对性能要求不高的场景:
def my_add(x, y):
return x + y
my_ufunc = np.frompyfunc(my_add, 2, 1)
result = my_ufunc([1, 2], [3, 4])
print(result) # 输出 [4 6]
• ufunc属性和方法:如np.add.reduce可对数组元素累加,np.add.accumulate可得到累加中间结果:
arr = np.array([1, 2, 3, 4])
reduced_result = np.add.reduce(arr) # 等同于sum(arr)
accumulated_result = np.add.accumulate(arr)
print(reduced_result) # 输出10
print(accumulated_result) # 输出 [1 3 6 10]
1. 统计函数在多维数据中的应用
对于多维数组,统计函数可按指定轴计算。计算二维数组的行均值、列均值、中位数等:
arr = np.random.rand(3, 4)
col_mean = np.mean(arr, axis=0) # 列均值
row_mean = np.mean(arr, axis=1) # 行均值
median = np.median(arr, axis=1) # 行中位数
std = np.std(arr) # 标准差
还可以进行条件统计,计算数组中大于某个值的元素之和:
arr = np.random.randint(1, 10, (5, 5))
sum_greater_than_5 = np.sum(arr[arr > 5])
2. 线性代数运算实战
矩阵乘法优化:矩阵乘法除了用@运算符,还可用np.dot。处理大型矩阵时,要注意数据类型和内存占用:
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result_dot = np.dot(A, B)
result_at = A @ B
• 求解线性方程组:使用np.linalg.solve求解线性方程组Ax = b :
A = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
x = np.linalg.solve(A, b)
• 特征值与特征向量:np.linalg.eig用于计算矩阵的特征值和特征向量:
A = np.array([[1, 2], [2, 1]])
values, vectors = np.linalg.eig(A)
1. 图像简单处理
借助PIL库读取图像并转为NumPy数组,进行灰度化和滤波处理。灰度化通过加权求和实现:
from PIL import Image
import numpy as np
from scipy.signal import convolve2d
# 读取图像并转为数组
img = Image.open('your_image.jpg')
img_arr = np.array(img)
# 灰度化处理
gray_img = np.dot(img_arr[..., :3], [0.299, 0.587, 0.114]).astype(np.uint8)
# 简单均值滤波
kernel = np.ones((3, 3)) / 9
filtered_img = convolve2d(gray_img, kernel, mode='same')
2. 数据模拟与分析
模拟随机漫步:模拟一维随机漫步,通过随机选择移动方向并累加:
steps = 1000
positions = np.zeros(steps)
moves = np.random.choice([-1, 1], steps)
positions = np.cumsum(moves)
• 简单数据分析:分析随机生成的学生成绩,计算平均分、及格率:
grades = np.random.randint(0, 100, 50)
average_grade = np.mean(grades)
pass_rate = np.sum(grades >= 60) / len(grades)
1. 避免循环,使用向量化操作
向量化操作利用底层优化库加速数组计算,比显式循环快得多。计算数组元素平方,向量化操作如下:
arr = np.arange(10000)
squares = arr ** 2 # 向量化操作
2. 合理指定数据类型
根据数据范围和精度需求指定数组数据类型,可减少内存占用、提高运算速度。如数据范围合适,可指定为np.int8 :
arr = np.array([1, 2, 3], dtype=np.int8)
通过本教程,我们深入学习了NumPy的中级实战技能,从数组的高级操作到复杂的数组运算,再到统计分析、线性代数以及实际案例应用和性能优化。
NumPy在科学计算、数据分析、机器学习等领域作用巨大 ,掌握这些技能能显著提升数据处理和计算效率。
在实际应用中,要不断实践,将NumPy与其他库(如Pandas、Matplotlib等)结合,以解决更复杂的问题,持续探索NumPy更多高级特性,挖掘其更大潜力。
来源:绿叶菜