SciPy与NumPy的关系

NPE*_*NPE 243 python numpy scipy

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

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

  • numpy.log10是一个返回NaNs为负参数的ufunc ;
  • scipy.log10 返回负参数的复数值,并且看起来不是ufunc.

同样可以说,大约log,log2logn,但不是关于log1p[2].

另一方面,numpy.exp并且scipy.exp对于相同的ufunc看起来是不同的名称.这也是真正的scipy.log1pnumpy.log1p.

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

为什么明显重复?如果这是numpyscipy命名空间的批量导入,为什么行为和缺失函数的微妙差异?是否有一些总体逻辑可以帮助消除混乱?

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

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

tal*_*ies 134

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

from numpy import *
Run Code Online (Sandbox Code Playgroud)

因此,在导入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 *
Run Code Online (Sandbox Code Playgroud)

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.
"""
Run Code Online (Sandbox Code Playgroud)

看来模块覆盖基础numpy的ufuncs为sqrt,log,log2,logn,log10,power,arccos,arcsin,和arctanh.这解释了你所看到的行为.为什么这样做的基本设计原因可能隐藏在某个地方的邮件列表中.

  • 在使用这些软件包一段时间后,我感觉到了这一点:NumPy是一个数值数组的库,供Python中需要这样一个对象的人使用.SciPy旨在成为科学家/工程师的库,因此它的目标是更严格的理论数学(因此包括log10的复数版本等).主要的困惑来自于NumPy保留了很多旧的子模块(应该已经进入Scipy),当时SciPy/NumPy之间的划分并不像今天那样清晰. (10认同)

Joh*_*ook 52

从SciPy参考指南:

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

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


PhM*_*hML 48

SciPy常见问题中看来,NumPy的一些函数出于历史原因而应该只出现在SciPy中:

NumPy和SciPy有什么区别?

在理想的世界中,NumPy只包含数组数据类型和最基本的操作:索引,排序,重新整形,基本元素函数等.所有数字代码都将驻留在SciPy中.然而,NumPy的一个重要目标是兼容性,因此NumPy试图保留其前任任何一个支持的所有功能.因此,NumPy包含一些线性代数函数,即使它们更恰当地属于SciPy.无论如何,SciPy包含更多全功能的线性代数模块版本,以及许多其他数值算法.如果你使用python进行科学计算,你应该安装NumPy和SciPy.大多数新功能属于SciPy而非NumPy.

这解释了为什么scipy.linalg.solve提供一些额外的功能numpy.linalg.solve.

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


dsh*_*ort 12

SciPy文档简介结尾处有一条简短的评论:

另一个有用的命令是source.当给定一个用Python编写的函数作为参数时,它会打印出该函数的源代码列表.这有助于学习算法或准确理解函数对其参数的作用.另外,不要忘记可以用来查看模块或包的命名空间的Python命令dir.

我认为这将允许对所涉及的所有软件包有足够知识的人精确地分辨出一些 scipy和numpy函数之间的差异(它根本没有帮我解决log10问题).我绝对没有那些知识,但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))
Run Code Online (Sandbox Code Playgroud)

这也是我的第一篇文章,所以如果我在这里改变一下,请告诉我.


Mu *_*ind 7

来自维基百科(http://en.wikipedia.org/wiki/NumPy#History):

数字代码经过调整,使其更具可维护性和灵活性,足以实现Numarray的新功能.这个新项目是SciPy的一部分.为了避免安装整个包只是为了得到一个数组对象,这个新包被分开并称为NumPy.

scipy为方便起见,它依赖于numpy并将许多numpy函数导入其命名空间.


Dav*_*veP 5

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