matrix
NumPy中该课程的状态是什么?
我一直被告知我应该改用ndarray
该类。matrix
在我编写的新代码中使用该类值得/安全吗?我不明白为什么我应该改用ndarray
s。
tl;
DR:
在numpy.matrix
类是越来越过时。有一些备受瞩目的库将类作为依赖项(最大的库scipy.sparse
),这妨碍了对类的适当短期弃用,但是强烈建议用户使用ndarray
类(通常使用numpy.array
便捷函数创建)。
。随着引入@
用于矩阵乘法的算子,许多矩阵的相对优势已被消除。
numpy.matrix
是的子类numpy.ndarray
。它最初是为了方便在涉及线性代数的计算中使用,但与更通用的数组类的实例相比,它们在行为方式上既有局限性,又有令人惊讶的差异。行为基本差异的示例:
np.matrix(np.random.rand(2,3))[None,...,None].shape == (1,2,3,1)
这并不具有任何实际意义)。arr[:,0]
和arr[0,:]
2d数组都为1d ndarray
,同时mat[:,0]
具有形状(N,1)
和mat[0,:]
形状(1,M)
(如果为)matrix
。mat1 * mat2
,if是有效的mat1.shape[1] == mat2.shape[0]
,但是ifarr1 * arr2
是有效的arr1.shape == arr2.shape
(当然,结果意味着完全不同的东西)。而且,令人惊讶地,mat1 / mat2
执行两个矩阵的 元素 除法。这种行为可能是继承自ndarray
矩阵,但对矩阵毫无意义,尤其是考虑到的含义*
。mat.A
与mat.A1
具有相同的值作为阵列的意见np.array(mat)
和np.array(mat).ravel()
分别。mat.T
并且mat.H
是矩阵的转置和共轭转置(伴随);arr.T
是该类存在的唯一此类属性ndarray
。最后mat.I
是的逆矩阵mat
。编写适用于ndarray或矩阵的代码非常容易。但是,当这两个类有可能必须在代码中进行交互时,事情就会变得困难起来。特别是,许多代码对于的子类自然 可以
正常工作ndarray
,但它们matrix
是行为不端的子类,很容易破坏试图依赖鸭子类型的代码。考虑以下使用数组和形状矩阵的示例(3,4)
:
import numpy as np
shape = (3, 4)
arr = np.arange(np.prod(shape)).reshape(shape) # ndarray
mat = np.matrix(arr) # same data in a matrix
print((arr + mat).shape) # (3, 4), makes sense
print((arr[0,:] + mat[0,:]).shape) # (1, 4), makes sense
print((arr[:,0] + mat[:,0]).shape) # (3, 3), surprising
根据我们沿切片的尺寸,将两个对象的切片相加会发生灾难性的变化。当形状相同时,对矩阵和数组的加法都会逐元素进行。上面的前两种情况很直观:我们添加两个数组(矩阵),然后分别添加两个行。最后一种情况确实令人惊讶:我们可能打算添加两列,最后得到一个矩阵。原因当然是arr[:,0]
具有(3,)
与形状兼容(1,3)
但mat[:.0]
具有形状的形状(3,1)
。两者一起广播以成形(3,3)
。
最后,当在python
3.5中引入了@
matmul运算符时(首先在numpy
1.10中实现),消除了矩阵类的最大优点(即,可以简洁地公式化涉及许多矩阵乘积的复杂矩阵表达式的可能性)。比较简单的二次形式的计算:
v = np.random.rand(3); v_row = np.matrix(v)
arr = np.random.rand(3,3); mat = np.matrix(arr)
print(v.dot(arr.dot(v))) # pre-matmul style
# 0.713447037658556, yours will vary
print(v_row * mat * v_row.T) # pre-matmul matrix style
# [[0.71344704]]
print(v @ arr @ v) # matmul style
# 0.713447037658556
综上所述,很明显为什么矩阵类在处理线性代数方面广受青睐:infix*
运算符使表达式的冗长程度降低,并且易于阅读。但是,@
使用现代python和numpy的运算符具有相同的可读性。此外,请注意,矩阵案例为我们提供了形状(1,1)
上应为标量的形状矩阵。这也意味着我们不能将列向量与这个“标量”相乘:(v_row * mat * v_row.T) * v_row.T
在上面的示例中,由于矩阵的形状不同(1,1)
,(3,1)
无法按此顺序相乘,因此会产生错误。
为了完整起见,应该注意的是,尽管matmul运算符修复了ndarrays与矩阵相比不是最理想的最常见方案,但是使用ndarrays优雅地处理线性代数仍然存在一些缺点(尽管人们仍然倾向于认为总体而言最好坚持使用后者)。一个这样的例子是矩阵幂:是矩阵mat ** 3
的适当的第三矩阵幂(而它是ndarray的元素级立方)。不幸的numpy.linalg.matrix_power
是更加冗长。此外,就地矩阵乘法仅适用于矩阵类。相比之下,虽然PEP
465和python语法都允许@=
使用matmul进行增强分配,但从numpy 1.15开始,对于ndarrays尚未实现此功能。
考虑到上述有关matrix
该类的复杂性,很长一段时间以来一直在反复讨论其可能被弃用。引入@
infix运算符是此过程的巨大先决条件,发生于2015年9月。不幸的是,矩阵类在早期的优点意味着它的使用范围很广。有些库依赖于矩阵类(最重要的依赖项之一是scipy.sparse
使用numpy.matrix
语义,并且在进行密化时经常返回矩阵),因此完全弃用它们总是有问题的。
从2009年开始出现在一个小小的邮件列表线程中,我发现诸如
numpy是为满足通用计算需求而设计的,而不是数学的任何一个分支。nd数组对很多事情都非常有用。相比之下,例如Matlab最初被设计为线性代数封装的简单前端。就我个人而言,当我使用Matlab时,我发现这很尴尬-
我通常在写几行与线性代数无关的代码时,实际上每行几行都进行矩阵数学运算。因此,我更喜欢numpy的方式-代码的线性代数行越长越尴尬,但其余的则好得多。Matrix类是这种情况的例外:编写该类是为了提供一种表达线性代数的自然方法。但是,当您将矩阵和数组混合使用时,事情变得有些棘手,即使坚持使用矩阵也存在困惑和局限性-
如何表达行向量与列向量?在矩阵上迭代时会得到什么?等等关于这些问题的讨论很多,很多好主意,关于如何改进它的一些共识,但是没有一个熟练的人有足够的动力去做。
这些反映了矩阵类带来的好处和困难。我可以找到的最早的弃用建议是从2008年开始的,尽管部分原因是由于非直觉的行为,此行为自此发生了变化(特别是,对矩阵进行切片和迭代将产生(行)矩阵,这很可能是人们期望的)。该建议表明,这是一个极具争议的主题,并且矩阵乘法的中缀运算符至关重要。
我可以找到的下一个提及来自2014年,事实证明这是一个 非常
富有成果的话题。随后的讨论提出了一般情况下处理numpy子类的问题,该主题仍然很受关注。也有强烈的批评:
引发此讨论(在Github上)的是,不可能编写适用于以下情况的鸭子式代码:
- ndarrays
- 矩阵
- 稀疏稀疏矩阵
这三个词的语义是不同的。scipy.sparse在矩阵和ndarray之间,某些东西像矩阵一样随机工作,而另一些则不然。
加上一些夸张的说法,可以说,从开发人员的角度来看,np.matrix正在做,并且已经通过捣乱Python中ndarray语义的未声明规则而已经作恶了。
其次是关于矩阵可能的未来的许多有价值的讨论。即使@
当时没有运算符,对于矩阵类的弃用及其对下游用户的影响也有很多想法。据我所知,这种讨论直接导致了引入matmul的PEP
465的诞生。
在2015年初:
在我看来,np.matrix的“固定”版本应该(1)不是np.ndarray子类,并且(2)存在于第三方库中,而不是numpy本身。
我认为将np.matrix作为ndarray子类固定在当前状态下并不可行,但是即使固定的矩阵类也不真正属于numpy本身,而numpy的发布周期太长,并且实验的兼容性保证-
更不用说在numpy中仅存在矩阵类会导致新用户误入歧途。
一旦@
操作员可以使用一段时间,关于折旧的讨论再次浮出水面,引发了关于矩阵折旧与矩阵关系的话题scipy.sparse
。
最终,于2017年11月下旬采取了第一个弃用numpy.matrix
措施。关于班级的家属:
社区将如何处理scipy.sparse矩阵子类?这些仍然很常用。
他们已经很长时间没有去任何地方了(直到稀疏的ndarray至少实现了)。因此,np.matrix需要移动而不是删除。
(来源)和
虽然我想像任何人一样摆脱np.matrix,但很快就这样做 确实是 破坏性的。
那里有很多不懂的人写的小脚本。我们确实希望他们学习不使用np.matrix,但是破坏所有脚本是一种痛苦的方式
由于scipy.sparse,像scikit-learn这样的大型项目根本无法替代使用np.matrix。
所以我认为前进的方向是这样的:
现在或每当有人聚集PR时:在np.matrix .__
init__中发出PendingDeprecationWarning(除非它会降低scikit-
learn和朋友的性能),并在文档顶部放置一个大警告框。这里的想法是实际上不破坏任何人的代码,而是开始传达出这样的信息:我们绝对不认为任何人如果有其他选择,都不应使用它。在使用scipy.sparse替代方法之后:增加警告,可能一直扩展到FutureWarning,以使现有脚本不会中断,但它们确实会发出嘈杂的警告
最终,如果我们认为这样可以减少维护成本:将其拆分为一个子包
(来源)。
截至2018年5月(numpy 1.15,相关的pull
request和commit),矩阵类docstring包含以下注释:
即使对于线性代数,也不再建议使用此类。而是使用常规数组。该类将来可能会被删除。
并且同时PendingDeprecationWarning
已将添加到matrix.__new__
。不幸的是,默认情况下,弃用警告(几乎总是)是静音的,因此大多数numpy的最终用户都不会看到此强烈提示。
最后,截至2018年11月的numpy路线图提到了多个相关主题,因为“ numpy社区将在以下方面投入资源和任务和功能之一 :
NumPy内部的某些内容实际上与NumPy的范围不匹配。
- numpy.fft的后端系统(因此,例如fft-mkl不需要猴子补丁numpy)
- 将掩码数组重写为不是ndarray子类-也许在单独的项目中?
- MaskedArray为鸭子数组类型,和/或
- 支持缺失值的dtypes
- 编写有关如何处理linalg和fft的numpy和scipy之间的重叠的策略(并实现它)。
- 弃用np.matrix
只要较大的库/许多用户(尤其是scipy.sparse
)依赖于矩阵类,这种状态就可能保持不变。但是,正在进行讨论以转移scipy.sparse
到其他方面,例如pydata/sparse
。无论弃用过程的发展如何,用户都应ndarray
在新代码中使用该类,并且如果可能的话,最好移植旧代码。最终,矩阵类可能最终会放在单独的程序包中,以消除因其以当前形式存在而造成的一些负担。
主要内容:逐元素矩阵乘法,矩阵乘积运算,矩阵点积矩阵乘法是将两个矩阵作为输入值,并将 A 矩阵的行与 B 矩阵的列对应位置相乘再相加,从而生成一个新矩阵,如下图所示: 注意:必须确保第一个矩阵中的行数等于第二个矩阵中的列数,否则不能进行矩阵乘法运算。 图1:矩阵乘法 矩阵乘法运算被称为向量化操作,向量化的主要目的是减少使用的 for 循环次数或者根本不使用。这样做的目的是为了加速程序的计算。 下面介绍 NumPy 提供的三种矩阵乘法,从而进一步
主要内容:matlib.empty(),numpy.matlib.zeros(),numpy.matlib.ones(),numpy.matlib.eye(),numpy.matlib.identity(),numpy.matlib.rand()NumPy 提供了一个 矩阵库模块 ,该模块中的函数返回的是一个 matrix 对象,而非 ndarray 对象。矩阵由 m 行 n 列(m*n)元素排列而成,矩阵中的元素可以是数字、符号或数学公式等。 matlib.empty() matlib.emp
问题内容: 我正在尝试创建具有混合数据类型(字符串,整数,整数)的NumPy数组/矩阵(Nx3)。但是,当我通过添加一些数据来添加此矩阵时,出现错误: TypeError:无效的类型提升 。拜托,有人可以帮我解决这个问题吗? 当我用示例数据创建一个数组时,NumPy将矩阵中的所有列都转换为一种“ S”数据类型。而且我无法为数组指定数据类型,因为当我执行此操作时, res = np.array([“
我需要在灰度图像中分割出异常。在算法的某个地方,我计算一个矩阵,其中包含需要设置为零的已知像素强度。我该怎么做? 例如: 计算的像素强度:(数组([94,95,96,97,98,99,100,101,102,103,104,105,106,107、108,109,110,111、112、113、114、115、116、117、118、119、120、121、122、123、124、125、126、
本文向大家介绍Python中的Numpy矩阵操作,包括了Python中的Numpy矩阵操作的使用技巧和注意事项,需要的朋友参考一下 Numpy 通过观察Python的自有数据类型,我们可以发现Python原生并不提供多维数组的操作,那么为了处理矩阵,就需要使用第三方提供的相关的包。 NumPy 是一个非常优秀的提供矩阵操作的包。NumPy的主要目标,就是提供多维数组,从而实现矩阵操作。 NumPy
问题内容: 我有以下代码: 它创建一个填充零的矩阵。相反,我想知道是否有一种函数或方法可以将它们初始化为s,而方法很简单。 问题答案: 您很少需要在numpy中进行矢量操作循环。您可以创建一个未初始化的数组并立即分配给所有条目: 我已经在这里和Blaenk发布的时间安排了时间: 时序显示优先选择作为更快的替代方案。OTOH,我喜欢numpy的便捷实现,在该实现中您可以同时为整个slice分配值,代