矩阵计算和 NumPy
NumPy(Numerical Python的缩写)是一个开源的 Python 库,广泛应用于科学计算中,特别是在数组计算、线性代数、傅里叶变换和随机数生成等领域。它提供了一个强大的 N 维数组对象和大量用于操作这些数组的函数和工具。很多高级科学计算工具包,比如 Pandas、Matplotlib 等都是基于 NumPy 的。
安装
NumPy 是个第三方包,如果还没有安装NumPy,可以通过以下命令安装:
pip install numpy
使用 NumPy 功能先要导入:
import numpy as np
下面示例代码,有些省略了导入过程了,测试时需要自行添加。
数组
NumPy 的核心特性之一是其 N 维数组(ndarray)对象。这是一个快速、灵活的大数据集容器。与 Python 原生的列表相比,NumPy 的数组更加高效,支持更高级的数学运算。下面是一些常用的数组操作。
创建数组
使用 np.array 函数,可以把其它类型的数据转换成 NumPy 数组:
# 把列表转换成数组
np_array = np.array([1, 2, 3, 4, 5])
# 把图片转换成二维数组
from PIL import Image
image = Image.open("example.jpg")
image_array = np.array(image)
使用 np.zeros,np.ones 函数可以创建特定大小的全零或全一数组:
zeros_array = np.zeros((2, 3)) # 创建一个 2x3 的零矩阵
ones_array = np.ones((3, 4)) # 创建一个 3x4 的单位矩阵
range_array = np.arange(10) # 创建一个元素值从 0 到 9 的数组
random_array = np.random.randint(0, 10, (3, 4)) # 创建一个 3x4 的矩阵,元素都是 0 到 9 的随机整数
数组形状和大小
shape 属性表示了数组形状:
import numpy as np
ones_array = np.ones((3, 4))
print(ones_array.shape) # 输出: (3, 4)
reshape 可以改变数组形状:
import numpy as np
# 创建一个一维数组
arr = np.arange(10) # 这将创建一个包含数字0到9的数组
print("原始数组:")
print(arr)
# 使用reshape将其重新排列成一个2x5的二维数组
reshaped_arr = arr.reshape((2, 5))
print("\n重塑后的二维数组:")
print(reshaped_arr)
# 也可以让NumPy自动计算其中一个维度的大小
# 下面的-1表示自动计算该维度的大小
reshaped_arr_2 = arr.reshape((5, -1))
print("\n自动计算维度的重塑数组:")
print(reshaped_arr_2)
输出:
原始数组:
[0 1 2 3 4 5 6 7 8 9]
重塑后的二维数组:
[[0 1 2 3 4]
[5 6 7 8 9]]
自动计算维度的重塑数组:
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
索引和切片
NumPy 一维数组索引方式与列表索引相同:
element = np_array[0] # 获取第一个元素
但是二维或更高维就不同了,对于二维数组(矩阵),索引方式通常是 array[row, column]
:
# 创建一个 3x3 的二维数组
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 访问第二行第三列的元素
print(arr[1, 2]) # 输出 6
NumPy 数组同样支持切片操作,规则与列表的切片相同:
# 访问第二行
print(arr[1, :]) # 输出 [4 5 6]
# 访问第三列
print(arr[:, 2]) # 输出 [3 6 9]
# 访问子矩阵(前两行,前两列)
print(arr[:2, :2]) # 输出 [[1 2] [4 5]]
NumPy 支持整数数组索引,可用来索引另一个数组:
print(arr[[0, 2], [1, 2]])
# 输出 [2 9] 也就是索引了两个数 arr[0, 1] 和 arr[2, 2]
按条件设置值
NumPy 还支持布尔索引,根据数组中元素的条件来索引:
# 创建一个布尔数组,表示元素是否大于5
bool_idx = arr > 5
# 使用布尔数组进行索引
print(arr[bool_idx]) # 输出 [6 7 8 9]
NumPy 支持布尔索引的这个特性可以给我们用来根据数组,甚至是另一个数组中每个元素的值,去更新当前数组中的元素。
例如,要将数组中所有小于零的元素改为0,可以这样做:
import numpy as np
# 创建一个示例数组
arr = np.array([1, -2, 3, -4, 5])
# 将所有小于零的元素改为0
arr[arr < 0] = 0
或者,假设有两个相同形状的数组 arr1 和 arr2,根据 arr2 中的条件来修改 arr1 中的元素:
import numpy as np
# 创建两个示例数组
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([5, 4, 3, 2, 1])
# 基于arr2中的条件(比如,元素值小于3)来修改arr1中的元素
condition = arr2 < 3 # arr2中元素小于3的条件
arr1[condition] = 0 # 将arr1中对应arr2条件为真的元素改为0
矩阵运算
NumPy 实现了所有常用的数学运算,我们无法一一介绍,这里着重演示一下,NumPy 最主要功能,矩阵的基本运算。
四则运算
最基础的自然是加减乘除:
import numpy as np
# 创建两个矩阵
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# 矩阵加法
addition = A + B
print("矩阵加法 A + B:\n", addition)
# 矩阵减法
subtraction = A - B
print("\n矩阵减法 A - B:\n", subtraction)
# 矩阵乘法(叉乘)
elementwise_multiplication = A * B
print("\n矩阵叉乘 A * B:\n", elementwise_multiplication)
# 矩阵乘法(点乘)
dot_product = np.dot(A, B)
print("\n矩阵点乘 A dot B:\n", dot_product)
# 矩阵除法(元素对元素)
elementwise_division = A / B
print("\n矩阵元素对元素除法 A / B:\n", elementwise_division)
输出:
矩阵加法 A + B:
[[ 6 8]
[10 12]]
矩阵减法 A - B:
[[-4 -4]
[-4 -4]]
矩阵叉乘 A * B:
[[ 5 12]
[21 32]]
矩阵点乘 A dot B:
[[19 22]
[43 50]]
矩阵元素对元素除法 A / B:
[[0.2 0.33333333]
[0.42857143 0.5 ]]
轴操作
在多维数据处理中,我们经常要沿着特定的轴(或维度)执行一些计算,例如计算总和、平均值、最大值和最小值等。以下是一些矩阵轴操作的示例程序。
import numpy as np
# 创建一个 3x3 的矩阵
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 计算所有元素的总和
total_sum = np.sum(matrix)
print("矩阵所有元素的总和:", total_sum)
# 计算每列的总和
col_sum = np.sum(matrix, axis=0)
print("每列的总和:", col_sum)
# 计算每行的总和
row_sum = np.sum(matrix, axis=1)
print("每行的总和:", row_sum)
# 计算每列的平均值
col_mean = np.mean(matrix, axis=0)
print("每列的平均值:", col_mean)
# 计算每行的平均值
row_mean = np.mean(matrix, axis=1)
print("每行的平均值:", row_mean)
# 计算每列的最大值
col_max = np.max(matrix, axis=0)
print("每列的最大值:", col_max)
# 计算每行的最大值
row_max = np.max(matrix, axis=1)
print("每行的最大值:", row_max)
线性代数操作
矩阵乘法、求逆等
import numpy as np
# 创建两个矩阵
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
B = np.array([[9, 8, 7], [6, 5, 4], [3, 2, 1]])
# 矩阵转置
transpose_A = A.T
transpose_B = B.T
# 尝试求矩阵A的逆(如果可能)
try:
inverse_A = np.linalg.inv(A)
except np.linalg.LinAlgError:
inverse_A = "不可逆"
# 打印结果
print("矩阵 A:\n", A)
print("矩阵 B:\n", B)
print("A 的转置:\n", transpose_A)
print("B 的转置:\n", transpose_B)
print("A 的逆:\n", inverse_A)