SciPy和NumPy之间的关系


253

SciPy似乎在其自己的名称空间中提供了NumPy的大多数(但不是全部[1])功能。换句话说,如果有一个名为的函数numpy.foo,则几乎可以肯定有一个scipy.foo。在大多数情况下,两者看起来是完全相同的,甚至有时指向相同的功能对象。

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

  • numpy.log10是一个ufunc该返回的NaN为负参数;
  • scipy.log10 返回负参数的复数值,并且似乎不是ufunc。

同样可以说,大约loglog2logn,但不是关于log1p[2]。

另一方面,numpy.expscipy.exp似乎对于同一ufunc是不同的名称。scipy.log1p和的情况也是如此numpy.log1p

另一个例子是numpy.linalg.solveVS scipy.linalg.solve。它们相似,但是后者比前者提供了一些附加功能。

为什么出现明显的重复?如果这意味着要的批发进口numpyscipy命名空间,为什么在行为的细微差别和缺少的功能?是否有一些有助于消除混乱的总体逻辑?

[1] ,,numpy.min 和其他几个人都在没有同行的命名空间。numpy.maxnumpy.absscipy

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


7
我在答案中读到,all of those functions are available without additionally importing Numpy因为the intention is for users not to have to know the distinction between the scipy and numpy namespaces。现在我很纳闷,因为我关注有关numpy和scipy的帖子,并且自己使用了它。而且我几乎总是看到numpy被单独导入(如np)。他们失败了吗?
joris 2011年

8
scipy和numpy在FFT方面有一些区别,我曾经被一个问题所困扰,最终导致scipy和numpy的rfft版本定义不同
wim 2011年

1
SciPy和NumPy的FFT不同。SciPy使用Fortran库FFTPACK,因此命名为scipy.fftpack。NumPy使用一个名为fftpack_lite的C库;它功能较少,仅在NumPy中支持双精度。思维公司 已修补其numpy.fft,以将Intel MKL用于FFT,而不是fftpack_lite。
Sturla Molden 2014年

7
NumPy最初名为scipy.core。NumPy和SciPy是密切相关的项目。分离的主要原因是要确保数组库(NumPy)精简且平均,因为不一定总是需要大量SciPy。此外,科学家们决定退役数字包(MIT)和numarray(NASA),转而使用scipy.core,因此它的名称为NumPy。SciPy仍未达到1.0,而NumPy当前发布为1.8.1。NumPy具有一些用于FFT和线性代数的功能,但不如SciPy广泛。
Sturla Molden 2014年

@SturlaMolden很了解Enthought,您知道Anaconda是同时优化还是仅优化numpy?
2015年

Answers:


138

上次我检查它时,scipy __init__方法执行

from numpy import *

以便在导入scipy模块时将整个numpy命名空间包含到scipy中。

log10您描述的行为很有趣,因为两个版本都来自numpy。一个是a 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 *

log10您获得scipy 的功能来自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的ufuncs sqrtloglog2lognlog10powerarccosarcsin,和arctanh。这就解释了您所看到的行为。这样做的根本设计原因可能埋在某个地方的邮件列表中。


10
在使用这些程序包一段时间后,我得到了这样的感觉:NumPy旨在成为数字数组的库,供在Python中需要此类对象的任何人使用。SciPy旨在成为科学家/工程师的图书馆,因此它的目标是建立更加严格的理论数学(因此包括log10的复数版本等)。主要的困惑来自于这样一个事实,即NumPy保留了许多旧的子模块(应该在Scipy中使用),这些子模块在SciPy / NumPy之间的界限不像现在这样清晰的时候被包括在内。
PhilMacKay 2014年

@PhilMacKay嗨,菲尔,我读了这篇文章以及您自2013年以来针对此numpy / scipy问题的其他帖子。我看到张贴者说scipy中有一些不等价的东西,并列举了abs,max和min作为示例,但我确实知道abs只是numpy.absolute的别名,并且有scipy.absolute,scipy.maximum和scipy .minimum。因此,以您的经验,到目前为止,如果您已经需要scipy,是否需要导入numpy?
Dan Boschen

@PhilMacKay似乎普遍共识是将SciPy的子模块库用于其相关用例,然后用于核心NumPy操作以专门导入NumPy(而不是原本需要导入的SciPy的顶层) )。由于某些原因,这被其他人以及SciPy文档本身称为更好的编码实践,并且我试图理解为什么会如此。我认为这是因为这是惯例问题,因此是可读性。您目前有何看法?
Dan Boschen

@DanBoschen截至2018年11月,我仍然支持上面的评论。仅需要NumPy时导入SciPy可能有点过头。另一方面,在加载SciPy时会导入NumPy,因此除了SciPy外,也无需导入NumPy。当然,遵循文档有很好的论据,因此可以根据自己的情况随意执行最相关的事情。
PhilMacKay

@PhilMacKay感谢您的输入。通过我的猜测进行了深思熟虑,为什么建议导入numpy(即使所有操作都可以在scipy中完成)却是一个惯例问题,因此对于共享代码而言可读性强。如果将所有特定于numpy的代码专门绑定到numpy库,则也可以更轻松地将其绑定到更大的scipy库中,该库包含很多未必需要的代码。就是说,我的想法(对于我自己的方法)是导入numpy,然后不导入顶级scipy,而是仅根据需要导入scipy子包。
Dan Boschen

52

从《 SciPy参考指南》中:

...所有的Nu​​mpy函数都已包含在scipy 名称空间中,因此所有这些函数都可用而无需另外导入Numpy。

目的是使用户不必知道scipynumpy名称空间之间的区别,尽管显然您已经发现了一个例外。


50

从看来 SciPy常见问题解答 NumPy的某些功能出于历史原因而在这里,而它仅应在SciPy中:

NumPy和SciPy有什么区别?

在理想的情况下,NumPy只会包含数组数据类型和最基本的操作:索引,排序,重塑,基本的元素函数等。所有数字代码都将驻留在SciPy中。但是,NumPy的重要目标之一是兼容性,因此NumPy尝试保留其前任任一个所支持的所有功能。因此,NumPy包含一些线性代数函数,即使这些函数更恰当地属于SciPy。无论如何,SciPy都包含线性代数模块的更多全功能版本,以及许多其他数值算法。如果您正在使用python进行科学计算,则可能应该同时安装NumPy和SciPy。大多数新功能属于SciPy,而不是NumPy。

这就解释了为什么scipy.linalg.solve在之上提供了一些附加功能numpy.linalg.solve

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


12

SciPy文档的简介末尾有一段简短的评论:

另一个有用的命令是source。当给定一个用Python编写的函数作为参数时,它将打印出该函数的源代码清单。这有助于学习算法或准确了解函数对其参数的作用。另外,不要忘记Python命令目录,该目录可用于查看模块或包的名称空间。

我认为,这将允许有人用所有的软件包足够的知识涉及挑开完全的差异是什么之间的一些 SciPy的和numpy的功能(它没有帮助我在所有的日志10题)。我绝对不具备这些知识,但是source确实表明了这一点,scipy.linalg.solvenumpy.linalg.solve以不同的方式与lapack进行了交互。

Python 2.4.3 (#1, May  5 2011, 18:44:23) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-50)] on linux2
>>> import scipy
>>> import scipy.linalg
>>> import numpy
>>> scipy.source(scipy.linalg.solve)
In file: /usr/lib64/python2.4/site-packages/scipy/linalg/basic.py

def solve(a, b, sym_pos=0, lower=0, overwrite_a=0, overwrite_b=0,
          debug = 0):
    """ solve(a, b, sym_pos=0, lower=0, overwrite_a=0, overwrite_b=0) -> x

    Solve a linear system of equations a * x = b for x.

    Inputs:

      a -- An N x N matrix.
      b -- An N x nrhs matrix or N vector.
      sym_pos -- Assume a is symmetric and positive definite.
      lower -- Assume a is lower triangular, otherwise upper one.
               Only used if sym_pos is true.
      overwrite_y - Discard data in y, where y is a or b.

    Outputs:

      x -- The solution to the system a * x = b
    """
    a1, b1 = map(asarray_chkfinite,(a,b))
    if len(a1.shape) != 2 or a1.shape[0] != a1.shape[1]:
        raise ValueError, 'expected square matrix'
    if a1.shape[0] != b1.shape[0]:
        raise ValueError, 'incompatible dimensions'
    overwrite_a = overwrite_a or (a1 is not a and not hasattr(a,'__array__'))
    overwrite_b = overwrite_b or (b1 is not b and not hasattr(b,'__array__'))
    if debug:
        print 'solve:overwrite_a=',overwrite_a
        print 'solve:overwrite_b=',overwrite_b
    if sym_pos:
        posv, = get_lapack_funcs(('posv',),(a1,b1))
        c,x,info = posv(a1,b1,
                        lower = lower,
                        overwrite_a=overwrite_a,
                        overwrite_b=overwrite_b)
    else:
        gesv, = get_lapack_funcs(('gesv',),(a1,b1))
        lu,piv,x,info = gesv(a1,b1,
                             overwrite_a=overwrite_a,
                             overwrite_b=overwrite_b)

    if info==0:
        return x
    if info>0:
        raise LinAlgError, "singular matrix"
    raise ValueError,\
          'illegal value in %-th argument of internal gesv|posv'%(-info)

>>> scipy.source(numpy.linalg.solve)
In file: /usr/lib64/python2.4/site-packages/numpy/linalg/linalg.py

def solve(a, b):
    """
    Solve the equation ``a x = b`` for ``x``.

    Parameters
    ----------
    a : array_like, shape (M, M)
        Input equation coefficients.
    b : array_like, shape (M,)
        Equation target values.

    Returns
    -------
    x : array, shape (M,)

    Raises
    ------
    LinAlgError
        If `a` is singular or not square.

    Examples
    --------
    Solve the system of equations ``3 * x0 + x1 = 9`` and ``x0 + 2 * x1 = 8``:

    >>> a = np.array([[3,1], [1,2]])
    >>> b = np.array([9,8])
    >>> x = np.linalg.solve(a, b)
    >>> x
    array([ 2.,  3.])

    Check that the solution is correct:

    >>> (np.dot(a, x) == b).all()
    True

    """
    a, _ = _makearray(a)
    b, wrap = _makearray(b)
    one_eq = len(b.shape) == 1
    if one_eq:
        b = b[:, newaxis]
    _assertRank2(a, b)
    _assertSquareness(a)
    n_eq = a.shape[0]
    n_rhs = b.shape[1]
    if n_eq != b.shape[0]:
        raise LinAlgError, 'Incompatible dimensions'
    t, result_t = _commonType(a, b)
#    lapack_routine = _findLapackRoutine('gesv', t)
    if isComplexType(t):
        lapack_routine = lapack_lite.zgesv
    else:
        lapack_routine = lapack_lite.dgesv
    a, b = _fastCopyAndTranspose(t, a, b)
    pivots = zeros(n_eq, fortran_int)
    results = lapack_routine(n_eq, n_rhs, a, n_eq, pivots, b, n_eq, 0)
    if results['info'] > 0:
        raise LinAlgError, 'Singular matrix'
    if one_eq:
        return wrap(b.ravel().astype(result_t))
    else:
        return wrap(b.transpose().astype(result_t))

这也是我的第一篇文章,因此如果我要在此处进行更改,请告诉我。


底层包装器非常不同。NumPy使用用C编写的薄层。SciPy使用f2py自动生成的层。SciPy始终与外部LAPACK库链接。如果未找到外部LAPACK,NumPy会使用自己的f2c'd lapack_lite。
Sturla Molden 2014年

8

从Wikipedia(http://en.wikipedia.org/wiki/NumPy#History):

修改了数字代码,使其更具可维护性和灵活性,足以实现Numarray的新颖功能。这个新项目是SciPy的一部分。为了避免仅为了获取数组对象而安装整个程序包,将此新程序包分开并称为NumPy。

scipy为了方便起见,依赖numpy并将许多numpy函数导入其名称空间。


4

关于linalg软件包-scipy函数将调用lapack和blas,它们在许多平台上都具有高度优化的版本,并且具有非常好的性能,尤其是对于在较大密度矩阵上的操作。另一方面,它们不是易于编译的库,需要fortran编译器和许多特定于平台的调整才能获得完整的性能。因此,numpy提供了许多常见线性代数函数的简单实现,这些函数通常足以满足许多目的。


numpy 1.10有一个不错的模块dual:“如果要使用numpy版本(如果可用),则该模块应同时用于numpy和scipy中的函数,否则,请使用scipy版本。” 用法---from numpy.dual import fft, inv
denis

1

从“ 定量经济学 ” 讲座

SciPy是一个软件包,其中包含使用NumPy构建的各种工具,这些工具使用其数组数据类型和相关功能

实际上,当我们导入SciPy时,我们也会得到NumPy,这可以从SciPy初始化文件中看到

# Import numpy symbols to scipy name space
import numpy as _num
linalg = None
from numpy import *
from numpy.random import rand, randn
from numpy.fft import fft, ifft
from numpy.lib.scimath import *

__all__  = []
__all__ += _num.__all__
__all__ += ['randn', 'rand', 'fft', 'ifft']

del _num
# Remove the linalg imported from numpy so that the scipy.linalg package can be
# imported.
del linalg
__all__.remove('linalg')

但是,显式使用NumPy功能是更常见和更好的做法

import numpy as np

a = np.identity(3)

在SciPy中有用的是其子包中的功能

  • scipy.optimize,scipy.integrate,scipy.stats等。

1
我看到您的评论,最好是显式使用NumPy功能,并且在SciPy教程中也看到了类似的说法,但是为什么会有这种更好的做法呢?似乎没有人回答。如果您已经在导入SciPy,并且它包含NumPy功能,为什么仍然最好导入NumPy?是不是当我们在SciPy中导入子包时,不是在导入顶层,因此不是采取具体步骤导入SciPy,而是应该为那些核心数组处理功能导入Numpy?
Dan Boschen

1

除了SciPy FAQ中描述的重复主要是为了向后兼容之外,在NumPy文档中进一步阐明说:

可选的SciPy加速例程(numpy.dual)

Scipy可能会加速的功能别名。

可以将SciPy构建为对FFT,线性代数和特殊函数使用加速或其他改进的库。该模块允许开发人员在SciPy可用时透明地支持这些加速功能,但仍支持仅安装NumPy的用户。

为简便起见,这些是:

  • 线性代数
  • 快速傅立叶变换
  • 第一种修改贝塞尔函数,阶数为0

另外,从SciPy教程中

SciPy的顶层还包含NumPy和numpy.lib.scimath中的函数。但是,最好直接从NumPy模块中使用它们。

因此,对于新应用程序,您应该首选在SciPy顶层重复的数组操作的NumPy版本。对于上面列出的域,您应该首选SciPy中的域,并在必要时在NumPy中检查向后兼容性。

以我的个人经验,我使用的大多数数组函数都位于NumPy的顶层(除外random)。但是,所有特定于域的例程都存在于SciPy的子包中,因此我很少使用SciPy顶层的任何东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.