Relación entre SciPy y NumPy

254

SciPy parece proporcionar la mayoría (pero no todas [1]) de las funciones de NumPy en su propio espacio de nombres. En otras palabras, si hay una función nombrada numpy.foo, es casi seguro que a scipy.foo. La mayoría de las veces, los dos parecen ser exactamente iguales, y muchas veces incluso apuntan al mismo objeto de función.

A veces son diferentes. Para dar un ejemplo que surgió recientemente:

  • numpy.log10es un ufunc que devuelve NaNs para argumentos negativos;
  • scipy.log10 devuelve valores complejos para argumentos negativos y no parece ser un ufunc.

Lo mismo puede decirse sobre log, log2y logn, pero no sobre log1p[2].

Por otro lado, numpy.expy scipy.expparecen ser nombres diferentes para el mismo ufunc. Esto también es cierto de scipy.log1py numpy.log1p.

Otro ejemplo es numpy.linalg.solvevs scipy.linalg.solve. Son similares, pero este último ofrece algunas características adicionales sobre el primero.

¿Por qué la aparente duplicación? Si se supone que esto es una importación total numpyen el scipyespacio de nombres, ¿por qué las sutiles diferencias de comportamiento y las funciones que faltan? ¿Existe alguna lógica general que ayudaría a aclarar la confusión?

[1] numpy.min, numpy.max, numpy.absy algunos otros no tienen homólogos en el scipyespacio de nombres.

[2] Probado con NumPy 1.5.1 y SciPy 0.9.0rc2.

NPE
fuente
77
Leí en las respuestas que all of those functions are available without additionally importing Numpyporque the intention is for users not to have to know the distinction between the scipy and numpy namespaces. Ahora me pregunto, porque sigo un poco las publicaciones sobre numpy y scipy y lo uso yo mismo. Y casi siempre veo que numpy se importa por separado (como np). ¿Entonces fallaron?
joris
8
hay algunas diferencias entre scipy y numpy en las cosas de FFT, una vez me mordió un problema que finalmente se rastreó hasta scipy y la versión de rmpt de numpy se definió de manera diferente
wim
1
Las FFT de SciPy y NumPy son diferentes. SciPy usa la biblioteca Fortran FFTPACK, de ahí el nombre scipy.fftpack. NumPy usa una biblioteca C llamada fftpack_lite; tiene menos funciones y solo admite doble precisión en NumPy. Enthought inc. ha parcheado su numpy.fft para usar Intel MKL para FFT en lugar de fftpack_lite.
Sturla Molden
77
NumPy fue originalmente llamado scipy.core. NumPy y SciPy son proyectos estrechamente relacionados. La razón principal de la separación es garantizar que la biblioteca de matrices (NumPy) sea simple y media, ya que la mayor parte de SciPy no siempre es necesaria. Además, hubo una decisión entre los científicos de retirar los paquetes de matrices numéricos (MIT) y numarray (NASA) a favor de scipy.core, y así recibió el nombre NumPy. SciPy aún no ha alcanzado 1.0, mientras que NumPy actualmente se publica como 1.8.1. NumPy tiene algunas facilidades para FFT y álgebra lineal, pero no tan extensa como SciPy.
Sturla Molden
@SturlaMolden es bueno saber acerca de Enthought, ¿sabes si Anaconda optimiza ambos o simplemente molesto?
guiones

Respuestas:

138

La última vez que lo revisé, el __init__método scipy ejecuta un

from numpy import *

para que todo el espacio de nombres numpy se incluya en scipy cuando se importe el módulo scipy.

El log10comportamiento que está describiendo es interesante, porque ambas versiones provienen de numpy. Uno es un ufunc, el otro es una numpy.libfunción. Por qué scipy prefiere la función de biblioteca sobre ufunc, no lo sé.


EDITAR: De hecho, puedo responder la log10pregunta. Mirando en el __init__método scipy veo esto:

# 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 *

La log10función que obtienes en scipy proviene numpy.lib.scimath. Mirando ese código, dice:

"""
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.
"""

Parece que las superposiciones de los módulos ufuncs numpy de base para sqrt, log, log2, logn, log10, power, arccos, arcsin, y arctanh. Eso explica el comportamiento que estás viendo. La razón de diseño subyacente por la que se hace así probablemente está enterrada en una publicación de la lista de correo en alguna parte.

talonmies
fuente
10
Después de trabajar a tiempo completo con estos paquetes por un tiempo, esta es la sensación que tengo al respecto: NumPy está destinado a ser una biblioteca para matrices numéricas, para ser utilizado por cualquiera que necesite dicho objeto en Python. SciPy está destinado a ser una biblioteca para científicos / ingenieros, por lo que apunta a una matemática teórica más rigurosa (por lo tanto, incluye una versión de número complejo de log10 y similares). La principal confusión proviene del hecho de que NumPy conserva muchos submódulos antiguos (que deberían haber entrado en Scipy) que se incluyeron en el momento en que la demarcación entre SciPy / NumPy no era tan clara como lo es hoy.
PhilMacKay
@PhilMacKay Hola Phil, leí esta y tu otra publicación específica de esta pregunta numpy / scipy de 2013. Mi pregunta es si tu opinión sigue siendo actual, como se indicó en tu comentario anterior. veo que el póster dice que hay algunos no equivalentes en scipy y enumera abs, max y min como ejemplos, pero entiendo que abs es solo un alias para numpy.absolute y hay un scipy.absolute, scipy.maximum y scipy .mínimo. Entonces, según su experiencia, ¿alguna vez ha necesitado importar numpy si ya necesita scipy?
Dan Boschen
@PhilMacKay Parece ser que el consenso general es utilizar las bibliotecas de submódulos de SciPy para sus casos de uso relevantes, y luego para que las operaciones centrales de NumPy importen NumPy específicamente (en lugar del nivel superior de SciPy que de lo contrario necesitaría importar ) Por alguna razón, esto lo afirman otros, así como la documentación de SciPy en sí misma, como una mejor práctica de codificación y estoy tratando de entender por qué sería importante. Supongo que es porque es una cuestión de convención y, por lo tanto, de legibilidad. ¿Cuál es tu opinión actual?
Dan Boschen
@DanBoschen A partir de noviembre de 2018, todavía mantengo mi comentario anterior. Importar SciPy cuando solo se necesita NumPy puede ser un poco exagerado. Por otro lado, NumPy se importa cuando se carga SciPy, por lo que no es necesario importar NumPy además de SciPy. Por supuesto, hay buenos argumentos para seguir la documentación, así que siéntase libre de hacer lo que sea más relevante en su propia situación.
PhilMacKay
@PhilMacKay Gracias por tu aporte. Habiendo pensado detenidamente por qué se sugiere importar numpy (aunque todo se puede hacer de manera descuidada) es una cuestión de convención y, por lo tanto, de legibilidad para el código compartido. Si todo el código específico de numpy está vinculado específicamente a la biblioteca de numpy, también se puede separar más fácilmente de estar vinculado a la biblioteca de scipy más grande que incluye mucho más que no siempre es necesario. Dicho esto, mi pensamiento (para mi propio enfoque) es importar numpy y luego NO importar el scipy de nivel superior, sino solo importar los subpaquetes scipy según sea necesario.
Dan Boschen el
52

De la Guía de referencia de SciPy:

... todas las funciones de Numpy se han incluido en el scipy espacio de nombres para que todas esas funciones estén disponibles sin importar Numpy adicionalmente.

La intención es que los usuarios no tengan que conocer la distinción entre los espacios de nombres scipyy numpy, aunque aparentemente han encontrado una excepción.

John D. Cook
fuente
50

Según las preguntas frecuentes de SciPy, algunas funciones de NumPy están aquí por razones históricas, mientras que solo deberían estar en SciPy:

¿Cuál es la diferencia entre NumPy y SciPy?

En un mundo ideal, NumPy no contendría nada más que el tipo de datos de la matriz y las operaciones más básicas: indexación, clasificación, remodelación, funciones básicas por elementos, etc. Todo el código numérico residiría en SciPy. Sin embargo, uno de los objetivos importantes de NumPy es la compatibilidad, por lo que NumPy intenta conservar todas las funciones compatibles con cualquiera de sus predecesores. Por lo tanto, NumPy contiene algunas funciones de álgebra lineal, aunque estas pertenecen más propiamente a SciPy. En cualquier caso, SciPy contiene versiones más completas de los módulos de álgebra lineal, así como muchos otros algoritmos numéricos. Si está haciendo computación científica con Python, probablemente debería instalar NumPy y SciPy. La mayoría de las nuevas características pertenecen a SciPy en lugar de NumPy.

Eso explica por qué scipy.linalg.solveofrece algunas características adicionales numpy.linalg.solve.

No vi la respuesta de SethMMorton a la pregunta relacionada

PhML
fuente
12

Hay un breve comentario al final de la introducción a la documentación de SciPy :

Otro comando útil es source. Cuando se le asigna una función escrita en Python como argumento, imprime una lista del código fuente de esa función. Esto puede ser útil para aprender sobre un algoritmo o para comprender exactamente qué hace una función con sus argumentos. Además, no olvide el directorio de comandos de Python que se puede usar para ver el espacio de nombres de un módulo o paquete.

Creo que esto permitirá que alguien con suficiente conocimiento de todos los paquetes involucrados separe exactamente cuáles son las diferencias entre algunas funciones escritas y numpy (no me ayudó en absoluto con la pregunta log10). Definitivamente no tengo ese conocimiento, pero sourcesí lo indico scipy.linalg.solvee numpy.linalg.solveinteractúo con lapack de diferentes maneras;

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))

Esta es también mi primera publicación, así que si debo cambiar algo aquí, avísenme.

dshort
fuente
Los envoltorios subyacentes son muy diferentes. NumPy usa una capa delgada escrita en C. SciPy usa una capa autogenerada por f2py. SciPy siempre se vincula con una biblioteca externa LAPACK. NumPy uses tiene su propio f2c'd lapack_lite en caso de que no se encuentre un LAPACK externo.
Sturla Molden
8

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

El código numérico se adaptó para hacerlo más fácil de mantener y lo suficientemente flexible como para implementar las nuevas funciones de Numarray. Este nuevo proyecto fue parte de SciPy. Para evitar instalar un paquete completo solo para obtener un objeto de matriz, este nuevo paquete se separó y se llamó NumPy.

scipydepende numpye importa muchas numpyfunciones en su espacio de nombres por conveniencia.

Mu Mind
fuente
4

Con respecto al paquete linalg, las funciones scipy llamarán lapack y blas, que están disponibles en versiones altamente optimizadas en muchas plataformas y ofrecen un rendimiento muy bueno, particularmente para operaciones en matrices densas razonablemente grandes. Por otro lado, no son bibliotecas fáciles de compilar, que requieren un compilador fortran y muchos ajustes específicos de la plataforma para obtener un rendimiento completo. Por lo tanto, numpy proporciona implementaciones simples de muchas funciones comunes de álgebra lineal que a menudo son lo suficientemente buenas para muchos propósitos.

DaveP
fuente
numpy 1.10 tiene un buen módulo dual: "Este módulo debe usarse para funciones tanto en numpy como scipy si desea utilizar la versión numpy si está disponible, pero la versión scipy de lo contrario". Uso ---from numpy.dual import fft, inv
denis
1

De conferencias sobre ' economía cuantitativa '

SciPy es un paquete que contiene varias herramientas que se construyen sobre NumPy, utilizando su tipo de datos de matriz y funcionalidad relacionada

De hecho, cuando importamos SciPy también obtenemos NumPy, como se puede ver en el archivo de inicialización de 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')

Sin embargo, es más común y una mejor práctica usar la funcionalidad NumPy explícitamente

import numpy as np

a = np.identity(3)

Lo que es útil en SciPy es la funcionalidad en sus subpaquetes

  • scipy.optimize, scipy.integrate, scipy.stats, etc.
Vlad Bezden
fuente
1
Veo su comentario de que es una mejor práctica usar la funcionalidad NumPy explícitamente, y veo que esto se repite en otros lugares, incluido el tutorial de SciPy, pero ¿por qué es esta mejor práctica? Nadie parece responder eso. Si ya está importando SciPy e incluye la funcionalidad NumPy, ¿por qué es mejor importar NumPy? ¿Es que cuando importamos un subpaquete en SciPy, NO estamos importando el nivel superior y, por lo tanto, en lugar de dar el paso para importar SciPy específicamente, deberíamos importar Numpy para esas funciones de procesamiento de matriz principal?
Dan Boschen
1

Además de las preguntas frecuentes de SciPy que describen la duplicación principalmente para la compatibilidad con versiones anteriores, se aclara en la documentación de NumPy para decir que

Opcionalmente, rutinas aceleradas por SciPy (numpy.dual)

Alias ​​para funciones que Scipy puede acelerar.

SciPy se puede construir para usar bibliotecas aceleradas o mejoradas para FFT, álgebra lineal y funciones especiales. Este módulo permite a los desarrolladores admitir de manera transparente estas funciones aceleradas cuando SciPy está disponible, pero aún admite usuarios que solo han instalado NumPy.

Por brevedad, estos son:

  • Álgebra lineal
  • FFT
  • La función Bessel modificada del primer tipo, orden 0

Además, del Tutorial SciPy :

El nivel superior de SciPy también contiene funciones de NumPy y numpy.lib.scimath. Sin embargo, es mejor usarlos directamente desde el módulo NumPy.

Por lo tanto, para nuevas aplicaciones, debe preferir la versión NumPy de las operaciones de matriz que se duplican en el nivel superior de SciPy. Para los dominios enumerados anteriormente, debe preferir aquellos en SciPy y verificar la compatibilidad con versiones anteriores si es necesario en NumPy.

En mi experiencia personal, la mayoría de las funciones de matriz que uso existen en el nivel superior de NumPy (a excepción de random). Sin embargo, todas las rutinas específicas de dominio existen en subpaquetes de SciPy, por lo que rara vez uso algo del nivel superior de SciPy.

jbbiomed
fuente