我问,因为我痛苦地了解到numpy做了许多似乎真正要求发生错误的事情,例如……
添加不同大小的矩阵(“广播”)而不抱怨:
In: np.array([1]) + np.identity(2) Out: array([[ 2.,1.],[ 1.,2.]])
根据输入返回不同的数据类型:
In: scalar1 = 1 In: scalar2 = 1. In: np.array(scalar1).dtype Out: dtype('int32') In: np.array(scalar2).dtype Out: dtype('float64')
或者根本不执行所需的操作(同样,取决于数据类型)而不引发任何警告:
In: np.squeeze(np.array([[1,1]])).ndim Out: 1 In: np.squeeze(np.matrix([[1,1]])).ndim Out: 2
这些都很难发现错误,因为它们不会引发任何异常或警告,并且通常会返回有效数据类型/形状的结果.因此,我的问题是:是否有任何一般指导方针可以改善安全性并防止数学编程中出现numpy错误?
[请注意,我不相信这个答案会吸引“自以为是的答案和讨论”,因为它不是关于个人建议,而是询问是否有关于这个主题的任何现有指南或来源 – 我找不到任何.]
解决方法
类型
squeeze示例围绕类型,ndarray类与np.matrix子类:
In [160]: np.squeeze(np.array([[1,1]])) Out[160]: array([1,1]) In [161]: np.squeeze(np.matrix([[1,1]])) Out[161]: matrix([[1,1]])
根据定义,np.matrix对象总是2d.这是重新定义ndarray操作的核心.
许多numpy函数将他们的工作委托给方法. fornp.squeeze`的代码是:
try: squeeze = a.squeeze except AttributeError: return _wrapit(a,'squeeze') try: # First try to use the new axis= parameter return squeeze(axis=axis) except TypeError: # For backwards compatibility return squeeze()
所以[161]真的是:
In [163]: np.matrix([[1,1]]).squeeze() Out[163]: matrix([[1,1]])
np.matrix.squeeze有自己的文档.
作为一般规则,我们不鼓励使用np.matrix.这是几年前创建的,为任性的MATLAB程序员提供了便利.那时候MATLAB只有2d矩阵(即使现在MATLAB’scalars’也是2d).
D型
np.array是一个强大的功能.通常它的行为是直观的,但有时它会做出太多的假设.
通常它从输入中获取线索,无论是整数,浮点数,字符串和/或列表:
In [170]: np.array(1).dtype Out[170]: dtype('int64') In [171]: np.array(1.0).dtype Out[171]: dtype('float64')
但它提供了许多参数.如果您需要更多控制,请使用它们:
array(object,dtype=None,copy=True,order='K',subok=False,ndmin=0) In [173]: np.array(1,float).dtype Out[173]: dtype('float64') In [174]: np.array('1',float).dtype Out[174]: dtype('float64') In [177]: np.array('1',dtype=float,ndmin=2) Out[177]: array([[1.]])
查看它的文档,以及列出许多其他数组创建函数的https://docs.scipy.org/doc/numpy/reference/routines.array-creation.html页面.看一下他们的代码.
例如,np.atleast_2d进行了大量的形状检查:
def atleast_2d(*arys): res = [] for ary in arys: ary = asanyarray(ary) if ary.ndim == 0: result = ary.reshape(1,1) elif ary.ndim == 1: result = ary[newaxis,:] else: result = ary res.append(result) if len(res) == 1: return res[0] else: return res
像这样的函数是防御性编程的好例子.
关于dtype = object的1d数组我们得到了很多问题.
In [272]: np.array([[1,2,3],[2,3]]) Out[272]: array([list([1,3]),list([2,3])],dtype=object)
np.array尝试创建一个具有统一dtype的多维数组.但是如果元素大小不同或者不能转换为相同的dtype,它将回退到对象dtype.这是我们需要注意形状和dtype的情况之一.
广播
广播一直是numpy的一部分,并且无法将其关闭. Octave和MATLAB稍后添加了它,并启用了警告开关.
第一个防御步骤是了解广播原则,即
>它可以扩展起始尺寸以匹配
>它强制统一尺寸匹配.
所以一个基本的例子是:
In [180]: np.arange(3)[:,None] + np.arange(4) Out[180]: array([[0,1,[1,3,4],4,5]])
第一项是(3),扩展为(3,1).第二个是(4,),通过广播扩展到(1,4). (3,1)和(1,4)一起广播到(3,4).
许多numpy函数都有参数,可以更容易地跟踪尺寸.例如sum(和其他)有一个keepdims参数:
In [181]: arr = _ In [182]: arr.sum(axis=0) Out[182]: array([ 3,6,9,12]) # (4,) shape In [183]: arr.sum(axis=0,keepdims=True) Out[183]: array([[ 3,12]]) # (1,4) shape In [184]: arr/_ # (3,4) / (1,4) => (3,4) Out[184]: array([[0.,0.16666667,0.22222222,0.25 ],[0.33333333,0.33333333,0.33333333],[0.66666667,0.5,0.44444444,0.41666667]])
在这种情况下,keepdims不是必需的,因为(3,4)/(4,)有效.但是当轴= 1和时,形状变为(3,不能用(3,4)广播.但是(3,1)可以:
In [185]: arr/arr.sum(axis=1,keepdims=True) Out[185]: array([[0.,0.5 ],[0.1,0.2,0.3,0.4 ],[0.14285714,0.21428571,0.28571429,0.35714286]])
为了管理我喜欢的形状:
>调试时显示形状
>以交互方式测试片段
>用诊断形状测试,例如np.arange(24).reshape(2,4)
>函数中的断言语句可以是有用的断言(arr.ndim == 1)
打字
https://docs.python.org/3/library/typing.html
即使对于内置的Python类型,它也是临时的.我不确定是否为numpy添加了很多东西.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。