SciPy与NumPy的关系

282 投票
8 回答
59344 浏览
提问于 2025-04-16 18:45

SciPy看起来提供了大部分(但不是全部[1])NumPy的功能,并且是在自己的命名空间下。换句话说,如果有一个叫做numpy.foo的函数,几乎可以肯定会有一个scipy.foo。大多数情况下,这两个函数看起来是完全相同的,很多时候它们甚至指向同一个函数。

不过,有时候它们是不同的。举个最近出现的例子:

  • numpy.log10是一个ufunc,对于负数参数会返回NaN(不是一个数字);
  • scipy.log10对于负数参数会返回复数值,并且似乎不是一个ufunc。

对于loglog2logn也是如此,但log1p就不一样了[2]。

另一方面,numpy.expscipy.exp看起来是同一个ufunc的不同名称。scipy.log1pnumpy.log1p也是如此。

另一个例子是numpy.linalg.solvescipy.linalg.solve。它们相似,但后者提供了一些额外的功能。

那么,为什么会有这种明显的重复呢?如果这是要将numpy整体导入到scipy的命名空间中,为什么会有行为上的细微差别和缺失的函数呢?有没有什么更大的逻辑可以帮助我们理清这些混乱呢?

[1] numpy.minnumpy.maxnumpy.abs和一些其他函数在scipy命名空间中没有对应的函数。

[2] 使用NumPy 1.5.1和SciPy 0.9.0rc2进行测试。

8 个回答

56

SciPy的常见问题解答来看,NumPy中的一些函数存在是因为历史原因,其实这些函数应该只在SciPy中。

NumPy和SciPy有什么区别?

在理想情况下,NumPy应该只包含数组这种数据类型和一些最基本的操作,比如索引、排序、重塑形状、基本的逐元素函数等等。所有的数值计算代码应该放在SciPy里。不过,NumPy的一个重要目标是兼容性,所以它尽量保留之前版本支持的所有功能。因此,NumPy里有一些线性代数的函数,尽管这些函数更适合放在SciPy里。总的来说,SciPy提供了更全面的线性代数模块,还有很多其他的数值算法。如果你在用Python进行科学计算,建议你同时安装NumPy和SciPy。大多数新功能应该放在SciPy里,而不是NumPy。

这也解释了为什么scipy.linalg.solvenumpy.linalg.solve多了一些额外的功能。

我没有看到SethMMorton对相关问题的回答。

59

来自SciPy参考指南:

... 所有的Numpy函数都已经被整合进了scipy这个命名空间,这样用户就可以直接使用这些函数,而不需要额外导入Numpy。

这样做的目的是让用户不需要了解scipynumpy这两个命名空间之间的区别,尽管显然你发现了一个例外。

155

上次我查看的时候,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 函数,包括 sqrtloglog2lognlog10powerarccosarcsinarctanh。这就解释了你看到的行为。至于为什么这样设计,可能在某个邮件列表的帖子里有提到。

撰写回答