SciPy与NumPy的关系
SciPy看起来提供了大部分(但不是全部[1])NumPy的功能,并且是在自己的命名空间下。换句话说,如果有一个叫做numpy.foo
的函数,几乎可以肯定会有一个scipy.foo
。大多数情况下,这两个函数看起来是完全相同的,很多时候它们甚至指向同一个函数。
不过,有时候它们是不同的。举个最近出现的例子:
numpy.log10
是一个ufunc,对于负数参数会返回NaN(不是一个数字);scipy.log10
对于负数参数会返回复数值,并且似乎不是一个ufunc。
对于log
、log2
和logn
也是如此,但log1p
就不一样了[2]。
另一方面,numpy.exp
和scipy.exp
看起来是同一个ufunc的不同名称。scipy.log1p
和numpy.log1p
也是如此。
另一个例子是numpy.linalg.solve
和scipy.linalg.solve
。它们相似,但后者提供了一些额外的功能。
那么,为什么会有这种明显的重复呢?如果这是要将numpy
整体导入到scipy
的命名空间中,为什么会有行为上的细微差别和缺失的函数呢?有没有什么更大的逻辑可以帮助我们理清这些混乱呢?
[1] numpy.min
、numpy.max
、numpy.abs
和一些其他函数在scipy
命名空间中没有对应的函数。
[2] 使用NumPy 1.5.1和SciPy 0.9.0rc2进行测试。
8 个回答
从SciPy的常见问题解答来看,NumPy中的一些函数存在是因为历史原因,其实这些函数应该只在SciPy中。
NumPy和SciPy有什么区别?
在理想情况下,NumPy应该只包含数组这种数据类型和一些最基本的操作,比如索引、排序、重塑形状、基本的逐元素函数等等。所有的数值计算代码应该放在SciPy里。不过,NumPy的一个重要目标是兼容性,所以它尽量保留之前版本支持的所有功能。因此,NumPy里有一些线性代数的函数,尽管这些函数更适合放在SciPy里。总的来说,SciPy提供了更全面的线性代数模块,还有很多其他的数值算法。如果你在用Python进行科学计算,建议你同时安装NumPy和SciPy。大多数新功能应该放在SciPy里,而不是NumPy。
这也解释了为什么scipy.linalg.solve
比numpy.linalg.solve
多了一些额外的功能。
我没有看到SethMMorton对相关问题的回答。
来自SciPy参考指南:
... 所有的Numpy函数都已经被整合进了
scipy
这个命名空间,这样用户就可以直接使用这些函数,而不需要额外导入Numpy。
这样做的目的是让用户不需要了解scipy
和numpy
这两个命名空间之间的区别,尽管显然你发现了一个例外。
上次我查看的时候,scipy的 __init__
方法会执行一个
from numpy import *
这样在导入scipy模块时,整个numpy的命名空间都会被包含进来。
你提到的 log10
的表现很有趣,因为这两种版本都是来自numpy的。其中一个是 ufunc
,另一个是 numpy.lib
的函数。我不太清楚为什么scipy会更倾向于使用库函数而不是 ufunc
。
补充一下:其实我可以回答关于 log10
的问题。在查看scipy的 __init__
方法时,我发现了这个:
# Import numpy symbols to scipy name space
import numpy as _num
from numpy import oldnumeric
from numpy import *
from numpy.random import rand, randn
from numpy.fft import fft, ifft
from numpy.lib.scimath import *
你在scipy中得到的 log10
函数是来自 numpy.lib.scimath
。看那段代码,它说:
"""
Wrapper functions to more user-friendly calling of certain math functions
whose output data-type is different than the input data-type in certain
domains of the input.
For example, for functions like log() with branch cuts, the versions in this
module provide the mathematically valid answers in the complex plane:
>>> import math
>>> from numpy.lib import scimath
>>> scimath.log(-math.exp(1)) == (1+1j*math.pi)
True
Similarly, sqrt(), other base logarithms, power() and trig functions are
correctly handled. See their respective docstrings for specific examples.
"""
这个模块似乎覆盖了基础的numpy ufunc
函数,包括 sqrt
、log
、log2
、logn
、log10
、power
、arccos
、arcsin
和 arctanh
。这就解释了你看到的行为。至于为什么这样设计,可能在某个邮件列表的帖子里有提到。