写点什么

结合 scipy.linalg 在 Python 中使用线性系统

发布于: 3 小时前

​​​​​​​​​​​​​​​​​​​​​​​​​​摘要:将线性代数概念应用到实际问题中 scipy.linalg 使用 Python 和 NumPy 处理向量和矩阵 使用线性系统模拟实际问题 使用求解线性系统 scipy.linalg


本文分享自华为云社区《使用scipy.linalg在Python中使用线性系统》,作者:Yuchuan。

 

线性代数广泛应用于各种学科,一旦您使用向量线性方程等概念组织信息,您就可以用它来解决许多问题。在 Python 中,与该主题相关的大多数例程都在中实现 scipy.linalg,它提供了非常快速的线性代数功能。


尤其是,线性系统在模拟各种现实世界问题中发挥着重要作用,并 scipy.linalg 提供了以有效方式研究和解决这些问题的工具。


在本教程中,您将学习如何:


  • 线性代数概念应用到实际问题中 scipy.linalg

  • 使用 Python 和 NumPy 处理向量矩阵

  • 使用线性系统模拟实际问题

  • 如何使用线性系统求解 scipy.linalg


让我们开始吧!

入门 scipy.linalg


SciPy 是一个用于科学计算的开源 Python 库,包括用于科学和工程中常见任务的几个模块,例如线性代数、优化、积分、插值和信号处理。它是 SciPy 堆栈的一部分,其中包括其他几个用于科学计算的包,例如 NumPy、Matplotlib、SymPy、IPython 和 pandas。


线性代数是数学的一个分支,涉及线性方程及其使用向量和矩阵的表示。它是用于多个工程领域的基础学科,也是深入了解机器学习的先决条件。


scipy.linalg 包括用于处理线性代数问题的多种工具,包括用于执行矩阵计算的函数,例如行列式、逆矩阵、特征值、特征向量和奇异值分解。


在本教程中,您将使用 from 的一些函数 scipy.linalg 来解决涉及线性系统的实际问题。为了使用 scipy.linalg,您必须安装和设置 SciPy 库,您可以使用 AnacondaPython 发行版和 conda 包和环境管理系统来完成。


注意:要了解有关 Anaconda 和 conda 的更多信息,请查看在 Windows 上设置 Python 进行机器学习。

首先,创建一个 conda 环境并激活它:


$ conda create --name linalg$ conda activate linalg
复制代码


激活 conda 环境后,您的提示将显示其名称 linalg.然后你可以在环境中安装必要的包:


(linalg) $ conda install scipy jupyter
复制代码


执行此命令后,系统应该需要一段时间才能确定依赖项并继续安装。


注意:除了 SciPy,您还将使用 JupyterNotebook 在交互式环境中运行代码。这样做不是强制性的,但它有助于处理数值和科学应用程序。


有关使用 JupyterNotebooks 的复习,请查看 JupyterNotebook:简介。


如果您更喜欢使用不同的 Python 发行版和 pip 包管理器来阅读本文,请展开下面的可折叠部分以了解如何设置您的环境。


设置环境使用 pip 显示隐藏


在打开 JupyterNotebook 之前,您需要注册 condalinalg 环境,以便您可以使用它作为内核来创建 Notebook。为此,在 linalg 激活环境的情况下,运行以下命令:


(linalg) $ python -m ipykernel install --user --name linalg
复制代码


现在您可以通过运行以下命令打开 JupyterNotebook:


$ jupyter notebook
复制代码


在浏览器中加载 Jupyter 后,通过点击创建一个新的笔记本电脑新→linalg,如下图所示:



内的笔记本电脑,你可以测试是否安装成功通过导入的 scipy 包:>>> 


In [1]: import scipy
复制代码


现在您已经完成了环境的设置,您将看到如何在 Python 中使用向量和矩阵,这是使用 scipy.linalg 线性代数应用程序的基础。

使用 NumPy 处理向量和矩阵


矢量是用来表示物理量同时具有大小和方向的数学实体。它是解决工程和机器学习问题的基本工具,就像矩阵一样,用于表示向量变换等应用程序。


NumPy 是 Python 中处理矩阵和向量最常用的库,用于处理 scipy.linalg 线性代数应用程序。在本节中,您将了解使用它创建矩阵和向量并对其执行操作的基础知识。


要开始处理矩阵和向量,您需要在 JupyterNotebook 中做的第一件事是导入 numpy.通常的方法是使用别名 np:>>> 


In [2]: import numpy as np
复制代码


为了表示矩阵和向量,NumPy 使用一种称为 ndarray.要创建 ndarray 对象,您可以使用 np.array(),它需要一个类似数组的对象,例如列表或嵌套列表。


例如,假设您需要创建以下矩阵:



要使用 NumPy 创建它,您可以使用 np.array(),提供一个包含矩阵每一行元素的嵌套列表:>>> 


In [3]: A = np.array([[1, 2], [3, 4], [5, 6]])   ...: AOut[3]:array([[1, 2],       [3, 4],       [5, 6]])
复制代码


您可能会注意到,NumPy 提供了矩阵的可视化表示,您可以在其中识别其列和行。


值得注意的是,NumPy 数组的元素必须是相同类型的。您可以使用以下方法检查 NumPy 数组的类型

.dtype:>>> 


In [4]: A.dtypeOut[4]:dtype('int64')
复制代码


由于的所有元素 A 都是整数,因此数组是用 type 创建的 int64。如果元素之一是 float,则将使用 type 创建数组 float64:


In [5]: A = np.array([[1.0, 2], [3, 4], [5, 6]])   ...: AOut[5]:array([[1., 2.],       [3., 4.],       [5., 6.]])
In [6]: A.dtypeOut[6]:dtype('float64')
复制代码


要检查 ndarray 对象的尺寸,您可以使用.shape.例如,要检查的尺寸 A,您可以使用 A.shape:>>> 


In [7]: A.shapeOut[7]:(3, 2)
复制代码


正如预期的那样,A 矩阵的维度是 3×2 因为 A 有三行和两列。


在处理涉及矩阵的问题时,您通常需要使用转置操作,它交换矩阵的列和行。


要转置由 ndarray 对象表示的向量或矩阵,您可以使用.transpose()或.T。例如,你可以得到的转 A 用 A.T:


In [8]: A.TOut[8]:array([[1., 3., 5.],       [2., 4., 6.]])
复制代码


通过换位,列 A 变成了行,A.T 行变成了列。


要创建向量,您可以使用 np.array(),提供包含向量元素的列表:>>> 


In [9]: v = np.array([1, 2, 3])   ...: vOut[9]:array([1, 2, 3])
复制代码


要检查向量的维度,您可以.shape 像以前一样使用:>>> 


In [10]: v.shapeOut[10]:(3,)
复制代码


请注意,此向量的形状是(3,)andnot(3,1)or(1,3)。这是一个 NumPy 功能,适用于那些习惯使用 MATLAB 的人。在 NumPy 中,可以创建一维数组,例如 v,这在执行矩阵和向量之间的操作时可能会导致问题。例如,转置操作对一维数组没有影响。


每当您向提供类似一维数组的参数时 np.array(),生成的数组将是一维数组。要创建二维数组,您必须提供类似二维数组的参数,例如嵌套列表:>>> 


In [11]: v = np.array([[1, 2, 3]])   ...: v.shapeOut[11]:(1, 3)
复制代码


在上述例子中,尺寸 v 是 1×3,其对应于一个两维的线矢量的尺寸。要创建列向量,您可以使用嵌套列表:>>> 


In [12]: v = np.array([[1], [2], [3]])   ...: v.shapeOut[12]:(3, 1)
复制代码


在这种情况下,尺寸 v 为 3×1,其对应于一个两维列向量的尺寸。


使用嵌套列表创建向量可能很费力,尤其是对于使用最多的列向量。作为替代方案,您可以创建一个一维向量,为提供一个平面列表 np.array,并用于.reshape()更改 ndarray 对象的维度:


In [13]: v = np.array([1, 2, 3]).reshape(3, 1)   ...: v.shapeOut[13]:(3, 1)
复制代码


在上面的示例中,您使用从.reshape()形状(3,1)为的一维向量获取形状的列向量(3,)。值得一提的是,.reshape()期望新数组的元素数与原数组的元素数兼容。换句话说,具有新形状的数组中的元素数必须等于原始数组中的元素数。


在这个例子中,你也可以在.reshape()不明确定义数组行数的情况下使用:>>> 


In [14]: v = np.array([1, 2, 3]).reshape(-1, 1)   ...: v.shapeOut[14]:(3, 1)
复制代码


在这里,-1 您提供的参数.reshape()表示新数组只有一列所需的行数,如第二个参数所指定。在这种情况下,由于原始数组具有三个元素,因此新数组的行数将为 3。


在实际应用中,您经常需要创建零、一或随机元素的矩阵。为此,NumPy 提供了一些方便的函数,接下来您将看到这些函数。

使用便捷函数创建数组


NumPy 还提供了一些方便的函数来创建数组。例如,要创建一个填充零的数组,您可以使用 np.zeros():>>> 


In [15]: A = np.zeros((3, 2))   ...: AOut[15]:array([[0., 0.],       [0., 0.],       [0., 0.]])
复制代码


作为它的第一个参数,np.zeros()需要一个元组来指示您要创建的数组的形状,它返回一个类型为的数组 float64。


同样,要创建填充数组,您可以使用 np.ones():>>> 


In [16]: A = np.ones((2, 3))   ...: AOut[16]:array([[1., 1., 1.],       [1., 1., 1.]])
复制代码


值得注意的是,np.ones()它还返回一个类型为的数组 float64。


要创建具有随机元素的数组,您可以使用 np.random.rand():


In [17]: A = np.random.rand(3, 2)   ...: AOut[17]:array([[0.8206045 , 0.54470809],       [0.9490381 , 0.05677859],       [0.71148476, 0.4709059 ]])
复制代码


np.random.rand()返回一个包含从 0 到的随机元素的数组 1,取自均匀分布。请注意,与

np.zeros()and 不同 np.ones(),np.random.rand()它不期望元组作为其参数。


同样,要从均值和单位方差为零的正态分布中获取随机元素的数组,您可以使用 np.random.randn():>>> 


In [18]: A = np.random.randn(3, 2)   ...: AOut[18]:array([[-1.20019512, -1.78337814],       [-0.22135221, -0.38805899],       [ 0.17620202, -2.05176764]])
复制代码


现在您已经创建了数组,您将看到如何使用它们执行操作。

对 NumPy 数组执行操作


在数组上使用加法(+)、减法(-)、乘法(*)、除法(/)和指数(**)运算符的常见 Python 运算始终按元素执行。如果操作数之一是标量,则将在标量和数组的每个元素之间执行操作。


例如,为了创建填充元素的矩阵等于 10,则可以使用 np.ones()由和乘法的输出 10 使用*:>>> 


In [19]: A = 10 * np.ones((2, 2))   ...: AOut[19]:array([[10., 10.],       [10., 10.]])
复制代码


如果两个操作数都是相同形状的数组,则将在数组的对应元素之间执行操作:>>> 


In [20]: A = 10 * np.ones((2, 2))   ...: B = np.array([[2, 2], [5, 5]])   ...: C = A * B   ...: COut[20]:array([[20., 20.],       [50., 50.]])
复制代码


在这里,您将 matrixA 的每个元素乘以 matrix 的相应元素 B。


要根据线性代数规则执行矩阵乘法,您可以使用 np.dot():>>> 


In [21]: A = np.array([[1, 2], [3, 4]])   ...: v = np.array([[5], [6]])   ...: x = np.dot(A, v)   ...: xOut[21]:array([[17],       [39]])
复制代码


在这里,您乘以一个 2×2 矩阵 A,该矩阵由一个名为的 2×1 向量命名 v。


您可以使用 @运算符获得相同的结果,从 PEP465 和 Python3.5 开始,NumPy 和本机 Python 都支持该运算符:


In [22]: A = np.array([[1, 2], [3, 4]])   ...: v = np.array([[5], [6]])   ...: x = A @ v   ...: xOut[22]:array([[17],       [39]])
复制代码


除了处理矩阵和向量的基本操作外,NumPy 还提供了一些特定的函数来处理 numpy.linalg.但是,对于这些应用程序,它 scipy.linalg 具有一些优势,您将在下面看到。

比较 scipy.linalg 用 numpy.linalg


NumPy 在 numpy.linalg 模块中包含一些用于处理线性代数应用程序的工具。但是,除非您不想将 SciPy 作为依赖项添加到项目中,否则通常最好使用 scipy.linalg,原因如下:


  • 由于在解释官方文档,scipy.linalg 包含了所有的功能 numpy.linalg,再加上一些额外的高级功能,不包括在 numpy.linalg。


  • scipy.linalg 编译时始终支持 BLAS 和 LAPACK,这些库包括用于以优化方式执行数值运算的例程。对于 numpy.linalg,BLAS 和 LAPACK 的使用是可选的。因此,根据您安装 NumPy 的方式,scipy.linalg 函数可能比 numpy.linalg


总之,考虑到科学和技术应用一般没有关于限制的依赖,它通常是一个好主意,安装 SciPy 的和使用 scipy.linalg 代替 numpy.linalg。


在下一节中,您将使用 scipy.linalg 工具来处理线性系统。您将首先通过一个简单的示例了解基础知识,然后将这些概念应用于实际问题。

使用 scipy.linalg.solve()求解线性系统


线性系统可以成为解决几个实际和重要问题的有用工具,包括与车辆交通、平衡化学方程式、电路和多项式插值相关的问题。


在本节中,您将学习如何使用 scipy.linalg.solve()来求解线性系统。但是在开始编写代码之前,了解基础知识很重要。

了解线性系统


线性系统,或者更精确地说,线性方程系统,是一组直线与一组变量方程。以下是与变量 x₁、x₂和 x₃相关的线性系统示例:



这里有涉及三个变量的三个方程。为了有一个线性系统,值ķ₁...ķ₉和 b₁...b₃必须是常数。


当只有两个或三个方程和变量时,可以手动执行计算、组合方程并找到变量的值。但是,对于四个或更多变量,手动求解线性系统需要相当长的时间,并且经常会出错。


实际应用通常涉及大量变量,这使得手动求解线性系统是不可行的。幸运的是,有一些工具可以完成这项艰巨的工作,例如 scipy.linalg.solve().

使用 scipy.linalg.solve()


SciPy 提供 scipy.linalg.solve()快速且可靠的方式求解线性系统。要了解它是如何工作的,请考虑以下系统:



为了使用 scipy.linalg.solve(),您首先需要将线性系统写为矩阵乘积,如下面的等式所示:



请注意,您将在计算矩阵乘积后得出系统的原始方程。scipy.linalg.solve()期望求解的输入是 matrixA 和 vectorb,您可以使用 NumPy 数组定义它们。这样,您可以使用以下代码解决系统问题:>>> 


1In [1]: import numpy as np 2   ...: from scipy.linalg import solve 3 4In [2]: A = np.array( 5   ...:    [ 6   ...:        [3, 2], 7   ...:        [2, -1], 8   ...:    ] 9   ...: )1011In [3]: b = np.array([12, 1]).reshape((2, 1))1213In [4]: x = solve(A, b)14   ...: x15Out[4]:16array([[2.],17       [3.]])
复制代码


以下是正在发生的事情的细分:


  • 第 1 行和第 2 行导入 NumPy np 以及 solve()fromscipy.linalg。

  • 第 4 到 9 行使用名为的 NumPy 数组创建系数矩阵 A。

  • 第 11 行使用名为的 NumPy 数组创建独立项向量 b。要使其成为具有两行的列向量,请使用.reshape((2,1))

  • 第 13 行和第 14 行调用 solve()求解由 A 和表征的线性系统 b,结果存储在中 x,并打印出来。请注意 solve(),即使原始数组的所有元素都是整数,也会返回带有浮点分量的解。


如果将原始方程中的 x₁=2 和 x₂=3 替换,则可以验证这是系统的解。


现在您已经了解了使用的基础知识 scipy.linalg.solve(),是时候了解线性系统的实际应用了。

解决实际问题:BuildingaMealPlan


通常使用线性系统解决的一类问题是当您需要找到获得某种混合物所需的组件比例时。下面,您将使用这个想法来制定膳食计划,混合不同的食物以获得均衡的饮食。


为此,请考虑均衡饮食应包括以下内容:

  • 170 单位维生素 A

  • 180 单位维生素 B

  • 140 单位维生素 C

  • 180 单位维生素 D

  • 350 单位维生素 E


你的任务是找出每种不同食物的数量,以获得指定数量的维生素。在下表中,您可以根据每种维生素的单位分析 1 克每种食物的结果:



通过将食物 1 表示为 x₁等,并考虑到您将混合 x₁单位的食物 1、x2 单位的食物 2 等等,您可以写出您所摄入的维生素 A 量的表达式 d 进入组合。考虑到均衡饮食应包含 170 个单位的维生素 A,您​​可以使用维生素 A 列中的数据写出以下等式:



对维生素 B、C、D 和 E 重复相同的过程,您会得到以下线性系统:



要使用 scipy.linalg.solve(),您必须获得系数矩阵 A 和独立项向量 b,它们由以下给出:



现在您只需使用 scipy.linalg.solve()来找出数量 x₁,…,x₅:>>> 


In [1]: import numpy as np   ...: from scipy.linalg import solve
In [2]: A = np.array( ...: [ ...: [1, 9, 2, 1, 1], ...: [10, 1, 2, 1, 1], ...: [1, 0, 5, 1, 1], ...: [2, 1, 1, 2, 9], ...: [2, 1, 2, 13, 2], ...: ] ...: )
In [3]: b = np.array([170, 180, 140, 180, 350]).reshape((5, 1))
In [4]: x = solve(A, b) ...: xOut[4]:array([[10.], [10.], [20.], [20.], [10.]])
复制代码


这表明均衡饮食应包括 10 食物单位 1、食物 10 单位 2、20 食物 20 单位 3、食物单位 4 和 10 食物单位 5。

结论


恭喜!您已经学习了如何使用一些线性代数概念以及如何使用 scipy.linalg 来解决涉及线性系统的问题。您已经看到向量和矩阵可用于表示数据,并且通过使用线性代数概念,您可以对实际问题进行建模并以有效的方式解决它们。


在本教程中,您学习了如何:


  • 线性代数概念应用到实际问题中 scipy.linalg

  • 使用 Python 和 NumPy 处理向量矩阵

  • 使用线性系统模拟实际问题

  • 使用求解线性系统 scipy.linalg


点击关注,第一时间了解华为云新鲜技术~​​​​

发布于: 3 小时前阅读数: 2
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
结合scipy.linalg在Python中使用线性系统