scipy和numpy之间的关系

scipy似乎在自己的命名空间中提供了大部分(但不是全部[1])的numpy函数。 换句话说,如果有一个名为numpy.foo的函数,几乎肯定有一个scipy.foo 。 大多数时候,两者看起来完全一样,往往甚至指向相同的function对象。

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

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

关于loglog2logn也可以这样说,但不是关于log1p [2]。

另一方面,对于相同的scipy.expnumpy.expscipy.exp似乎是不同的名称。 scipy.log1pnumpy.log1p也是如此。

另一个例子是numpy.linalg.solve vs scipy.linalg.solve 。 他们是相似的,但后者提供了一些额外的function,前者。

为什么表面上的重复? 如果这是为了批量导入scipy命名空间,为什么行为和缺失函数的细微差别? 是否有一些总体逻辑可以帮助消除混淆?

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

[2]使用numpy 1.5.1和scipy 0.9.0rc2进行testing。

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

 from numpy import * 

所以当scipy模块被导入时,整个numpy命名空间被包含在scipy中。

你所描述的log10行为很有趣,因为这两个版本都来自numpy。 一个是numpy.lib ,另一个是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. """ 

看来这个模块覆盖了sqrtloglog2lognlog10powerarccosarcsinarctanh的基本numpy arctanh 。 这就解释了你所看到的行为。 为什么这样做的基本devise原因可能被埋在一个邮件列表发布到某个地方。

从SciPy参考指南:

…所有的Nu​​mpy函数都被包含在scipy命名空间中,这样所有这些函数都可以使用,而不需要另外导入Numpy。

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

从scipy的FAQ看来,numpy的一些function在这里是出于历史原因,而它只能是scipy:

NumPy和SciPy有什么区别?

在理想的世界中,NumPy将只包含数组数据types和最基本的操作:索引,sorting,重塑,基本元素函数等等。 所有的数字代码将驻留在SciPy中。 然而,NumPy的重要目标之一是兼容性,所以NumPy试图保留其前任任何一个支持的所有function。 因此NumPy包含一些线性代数函数,尽pipe这些函数更适合于SciPy。 在任何情况下,SciPy都包含更全面的线性代数模块版本,以及许多其他数值algorithm。 如果你正在用python进行科学计算,你应该安装NumPy和SciPy。 大多数新function属于SciPy而不是NumPy。

这就解释了为什么scipy.linalg.solve提供了一些额外的function。

编辑:

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

在SciPy文档介绍结尾有一个简短的评论:

另一个有用的命令是source 。 当给定一个用Python编写的函数作为参数时,它会打印出该函数的源代码列表。 这对于学习algorithm或者理解一个函数正在做什么来说是有帮助的。 另外不要忘记可以用来查看模块或包的命名空间的Python命令dir。

我认为这样可以让一个对所有软件包有足够了解的人能够精确地分辨出一些 scipy和numpy函数之间的区别(它根本不能帮助我解决log10问题)。 我绝对没有这方面的知识,但是source确实表明scipy.linalg.solve和numpy.linalg.solve以不同的方式与numpy.linalg.solve交互;

 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 ``ax = 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)) 

这也是我的第一篇文章,所以如果我应该改变一些东西,请让我知道。

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

数字代码被修改以使其更具可维护性和灵活性,以实现Numarray的新颖特性。 这个新项目是SciPy的一部分。 为了避免安装一个完整的包来获得一个数组对象,这个新的包被分离并且被称为NumPy。

scipy依赖于numpy并且为了方便,将许多numpy函数导入到它的命名空间中。

关于linalg包 – scipy函数将调用lapack和blas,它们在许多平台上都有高度优化的版本,并且提供了非常好的性能,特别是在相当大的密集matrix上运行。 另一方面,它们不是很容易编译的库,需要Fortran编译器和许多平台特定的调整来获得完整的性能。 因此,numpy提供了许多常用线性代数函数的简单实现,这些函数对于很多目的来说通常是足够好的。

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

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

Scipy可以加速的function的别名。

可以构buildScipy来使用加速或改进的FFT库,线性代数和特殊函数。 该模块允许开发人员在scipy可用时透明地支持这些加速function,但仍支持仅安装Numpy的用户。

为简洁起见,这些是:

  • 线性代数
  • FFT
  • 第一种修改的贝塞尔函数,顺序为0

另外,从SciPy教程 :

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

因此,对于新的应用程序,您应该更喜欢在SciPy顶层重复使用的数组操作的NumPy版本。 对于上面列出的域名,您应该更喜欢SciPy中的那些域名,并在NumPy中检查是否需要向后兼容。

根据我个人的经验,我使用的大部分数组函数都存在于NumPy的顶层(除了random )。 然而,所有领域特定的例程都存在于SciPy的子包中,所以我很less使用SciPy的顶层的任何东西。

从“ 数量经济学 ”讲座

SciPy是一个包含NumPy之上构build的各种工具的包,使用它的数组数据types和相关的function

实际上,当我们导入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') 

但是,明确使用NumPyfunction更为常见和更好的做法

 import numpy as np a = np.identity(3) 

SciPy中有用的是其子包中的function

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