在包含对象的NumPy数组上定义数学运算(如sin…)
我想为一个模块创建的类似数字的对象提供“所有”数学函数(这个模块是uncertainties.py
,它可以进行带误差传播的计算)——这些对象是带有不确定性的数字。
那么,最好的方法是什么呢?
目前,我在uncertainties.py
模块中重新定义了大部分来自math
的函数,使它们可以处理带不确定性的数字。一个缺点是,想要使用from math import *
的用户必须在import uncertainties
之后再进行导入。
不过,与NumPy的交互目前仅限于基本操作(比如可以对带不确定性的数字数组进行加法等);它还不支持更复杂的函数(例如,sin()),这些函数可以在包含带不确定性数字的NumPy数组上使用。我目前的做法是建议用户定义sin = numpy.vectorize(math.sin)
,这样新的math.sin
函数(可以处理带不确定性的数字)就可以应用到任何NumPy数组的元素上。一个缺点是,用户需要为每个感兴趣的函数都这样做,比较麻烦。
所以,扩展像sin()
这样的数学函数,使它们能够方便地与简单数字和NumPy数组一起使用,最好的方法是什么呢?
NumPy选择的做法是定义自己的numpy.sin
,而不是修改math.sin
使其能够与NumPy数组一起使用。我是否也应该对我的uncertainties.py
模块采取同样的做法,停止重新定义math.sin
呢?
此外,定义sin
的最有效和正确的方法是什么,以便它能够同时处理简单数字、带不确定性的数字和NumPy数组?我重新定义的math.sin
已经可以处理简单数字和带不确定性的数字。然而,使用numpy.vectorize
将其向量化在“常规”NumPy数组上可能会比numpy.sin
慢得多。
1 个回答
看起来,按照NumPy自己的做法来处理事情会更清晰:一些“扩展”的数学运算(比如正弦函数sin等)可以放在一个单独的命名空间里。因此,NumPy有了numpy.sin
等函数。这些运算大多数情况下和math
库里的函数是兼容的,但它们也可以在NumPy数组上使用。
所以,我觉得那些应该同时适用于普通数字、NumPy数组以及带有不确定性的数字的数学函数,最好也是放在一个单独的命名空间里。比如,用户可以这样做:
from uncertainties import sin
或者
from uncertainties import * # sin, cos, etc.
为了优化,有一个替代方案就是提供两组不同的数学函数:一组是针对带有不确定性的普通数字的函数,另一组是针对带有不确定性的数组的函数:
from uncertainties.math_ops import * # Work on scalars and scalars with uncertainty
或者
from uncertainties.numpy_ops import * # Work on everything (scalars, arrays, numbers with uncertainties, arrays with uncertainties)