And*_*eak 44 python numpy matrix deprecated numpy-ndarray
matrixNumPy中班级的状态是什么?
我一直被告知我应该使用这门ndarray课程.matrix在我编写的新代码中使用类是否值得/安全?我不明白为什么我应该使用ndarrays代替.
And*_*eak 59
TL; 博士:该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,如果有效mat1.shape[1] == mat2.shape[0],arr1 * 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.编写适用于ndarrays或矩阵的代码非常容易.但是当两个类有可能在代码中进行交互时,事情开始变得困难.特别是,很多代码可以自然地用于子类ndarray,但是matrix是一个不良行为的子类,可以轻易地破坏试图依赖于duck类型的代码.考虑使用形状的数组和矩阵的以下示例(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).
最后,当在@dbthon 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
看看上面的内容,很明显为什么矩阵类广泛用于处理线性代数:中缀*运算符使表达式更简洁,更易于阅读.但是,我们@使用现代python和numpy 与操作员获得相同的可读性.此外,请注意矩阵情况为我们提供了一个形状矩阵,在(1,1)技术上应该是一个标量.这也意味着,我们不能繁殖的列矢量与该"标量":(v_row * mat * v_row.T) * v_row.T在上面的例子中引发错误,因为与形状基质(1,1)和(3,1)不能以该顺序相乘.
为了完整起见,应该注意的是,尽管matmul算子修复了与矩阵相比ndarray不是最理想的最常见场景,但是使用ndarrays优雅地处理线性代数仍然存在一些缺点(尽管人们仍然倾向于认为整体上它是最好坚持后者).一个这样的例子是矩阵幂:矩阵mat ** 3的适当的第三矩阵幂(而它是ndarray的元素立方体).不幸的numpy.linalg.matrix_power是,这更加冗长.此外,就地矩阵乘法仅适用于矩阵类.相比之下,尽管PEP 465和python语法都允许@=使用matmul作为增强赋值,但是对于numpar 1.15中的ndarrays,这没有实现.
考虑到上述matrix类别的复杂性,长期以来一直在讨论其可能的弃用问题.@这个过程的一个巨大先决条件的中缀运算符的引入发生在2015年9月.不幸的是,早期矩阵类的优点意味着它的使用范围很广.有些库依赖于矩阵类(其中一个最重要的依赖是scipy.sparse使用numpy.matrix语义并且通常在致密化时返回矩阵),因此完全弃用它们一直存在问题.
已经在2009年的一个numpy邮件列表线程中我发现了诸如此类的评论
numpy是为通用计算需求而设计的,而不是任何一个数学分支.nd-arrays对很多东西非常有用.相比之下,Matlab最初设计为线性代数包的简单前端.就个人而言,当我使用Matlab时,我发现非常尴尬 - 我通常编写100行与线性代数无关的代码行,对于实际进行矩阵数学的每几行.所以我更喜欢numpy的方式 - 代码的线性代数行更长,更尴尬,但其余的要好得多.
Matrix类是例外:is是为了提供表达线性代数的自然方式而编写的.然而,当你混合矩阵和数组时,事情变得有点棘手,即使坚持使用矩阵也存在混淆和限制 - 你如何表达行与列向量?迭代矩阵时你会得到什么?等等
有很多关于这些问题的讨论,很多好的想法,关于如何改进它的一点共识,但没有一个有技能的人有足够的动力去做.
这些反映了矩阵类带来的好处和困难.我可以找到的最早的弃用建议是从2008年开始,尽管部分原因是由于非直观的行为已经改变(特别是切片和迭代矩阵将导致(行)矩阵,因为人们很可能会期望).该建议表明这是一个备受争议的主题,并且用于矩阵乘法的中缀运算符至关重要.
我能找到的下一个提及是从2014年开始,结果证明这是一个非常富有成果的线索.随后的讨论提出了一般处理numpy子类的问题,这个一般主题仍然在桌面上.还有强烈的批评:
引发此讨论(在Github上)的原因是,不可能编写适用于以下情况的鸭类代码:
- ndarrays
- 矩阵
- scipy.sparse稀疏矩阵
这三者的语义不同; scipy.sparse介于矩阵和ndarray之间,有些东西像矩阵一样随机工作,而其他东西则没有.
随着一些hyberbole的添加,可以说从开发人员的角度来看,np.matrix正在做,并且已经通过现有的方式做了恶,通过搞乱Python中未说明的ndarray语义规则.
接下来是对矩阵可能的未来进行了大量有价值的讨论.即使@当时没有运算符,也会对矩阵类的弃用以及它如何影响下游用户有很多考虑.据我所知,这个讨论直接导致了PEP 465的推出,引入了matmul.
在我看来,np.matrix的"固定"版本应该(1)不是np.ndarray子类,(2)存在于第三方库中,而不是numpy本身.
我认为将np.matrix作为ndarray子类固定在当前状态是不可行的,但即使是固定矩阵类也不属于numpy本身,它具有太长的发布周期和实验的兼容性保证 - 更不用说在numpy中仅存在矩阵类会导致新用户误入歧途.
一旦@运营商已经有一段是可利用弃用的讨论再次浮出水面,reraising话题关于矩阵折旧和的关系scipy.sparse.
最终,在2017年11月下旬采取了首次弃用行动numpy.matrix.关于班上的家属:
社区如何处理scipy.sparse矩阵子类?这些仍然是常用的.
他们不会去任何地方很长一段时间(直到稀疏的ndarrays至少实现).因此,需要移动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,相关拉取请求和提交)矩阵类docstring包含以下注释:
不再建议使用此类,即使对于线性代数也是如此.而是使用常规数组.该课程将来可能会被删除.
并且同时PendingDeprecationWarning添加了一个matrix.__new__.不幸的是,默认情况下,弃用警告(几乎总是)会被静音,因此numpy的大多数最终用户都不会看到这种强烈暗示.
最后,截至2018年11月的numpy路线图提到了多个相关主题,作为" 任务和功能[numpy社区]将投入资源 "之一:
NumPy中的一些内容实际上与NumPy的范围不匹配.
- numpy.fft的后端系统(例如fft-mkl不需要monkeypatch numpy)
- 重写掩码数组不是一个ndarray子类 - 可能在一个单独的项目中?
- MaskedArray作为鸭子阵列类型,和/或
- 支持缺失值的dtypes
- 写一个关于如何处理linalg和fft(和实现它)的numpy和scipy之间重叠的策略.
- 弃用np.matrix
只要较大的库/许多用户(特别是scipy.sparse)依赖于矩阵类,这种状态就可能保持不变.但是,正在进行讨论,scipy.sparse以便依赖其他东西,例如pydata/sparse.无论弃用过程的发展如何,用户都应该ndarray在新代码中使用该类,并且如果可能的话,最好移植旧代码.最终,矩阵类可能最终会出现在一个单独的包中,以消除由于其当前形式存在而造成的一些负担.
| 归档时间: | 
 | 
| 查看次数: | 3431 次 | 
| 最近记录: |