python - con - ciencia de datos online
Relación entre ciencia y número (8)
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 llamada numpy.foo
, es casi seguro que hay un scipy.foo
. La mayoría de las veces, los dos parecen ser exactamente iguales, a menudo incluso apuntando al mismo objeto de función.
A veces, son diferentes. Para dar un ejemplo que surgió recientemente:
-
numpy.log10
es un ufunc que devuelve NaNs para argumentos negativos; -
scipy.log10
devuelve valores complejos para argumentos negativos y no parece ser un ufunc.
Lo mismo se puede decir sobre log
, log2
y logn
, pero no sobre log1p
[2].
Por otro lado, numpy.exp
y scipy.exp
parecen ser nombres diferentes para el mismo ufunc. Esto también es válido para scipy.log1p
y numpy.log1p
.
Otro ejemplo es numpy.linalg.solve
vs scipy.linalg.solve
. Son similares, pero el último ofrece algunas características adicionales sobre el primero.
¿Por qué la aparente duplicación? Si se pretende que esto sea una importación al por mayor de numpy
al espacio de nombres scipy
, ¿por qué las diferencias sutiles en el comportamiento y las funciones faltantes? ¿Hay alguna lógica general que ayude a aclarar la confusión?
[1] numpy.min
, numpy.max
, numpy.abs
y algunos otros no tienen equivalentes en el espacio de nombres scipy
.
[2] Probado usando NumPy 1.5.1 y SciPy 0.9.0rc2.
Además de las Preguntas Frecuentes de SciPy que describen la duplicación es principalmente para la compatibilidad con versiones anteriores, se aclara más en la documentación de NumPy para decir que
Opcionalmente rutinas aceleradas por SciPy (numpy.dual)
Alias para funciones que pueden ser aceleradas por Scipy.
SciPy puede construirse para usar bibliotecas aceleradas o mejoradas de otro modo para FFT, álgebra lineal y funciones especiales. Este módulo permite a los desarrolladores admitir estas funciones aceleradas de forma transparente cuando SciPy está disponible, pero aún así 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, desde el Tutorial de SciPy :
El nivel superior de SciPy también contiene funciones de NumPy y numpy.lib.scimath. Sin embargo, es mejor utilizarlos directamente desde el módulo NumPy.
Por lo tanto, para las nuevas aplicaciones, debería preferir la versión NumPy de las operaciones de matriz que están duplicadas en el nivel superior de SciPy. Para los dominios mencionados anteriormente, debería preferir los de 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 (excepto random
). Sin embargo, todas las rutinas específicas del dominio existen en subpaquetes de SciPy, por lo que rara vez uso algo del nivel superior de SciPy.
Con respecto al paquete linalg: las funciones scipy se denominarán lapack y blas, que están disponibles en versiones altamente optimizadas en muchas plataformas y ofrecen un rendimiento muy bueno, en particular para operaciones en matrices densamente razonables. Por otro lado, no son bibliotecas fáciles de compilar, ya que requieren un compilador fortran y muchos ajustes específicos de la plataforma para obtener el máximo rendimiento. 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.
De Wikipedia ( http://en.wikipedia.org/wiki/NumPy#History ):
El código numérico se adaptó para que sea más fácil de mantener y lo suficientemente flexible como para implementar las características novedosas 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.
scipy
depende del numpy
e importa muchas funciones de número en su espacio de nombres para su comodidad.
De la Guía de referencia SciPy:
... todas las funciones de Numpy se han incluido en el espacio de nombres
scipy
para que todas esas funciones estén disponibles sin importar adicionalmente Numpy.
La intención es que los usuarios no tengan que saber la distinción entre los numpy
nombres scipy
y numpy
, aunque aparentemente haya encontrado una excepción.
De las Preguntas Frecuentes de SciPy parece que 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 matriz y las operaciones más básicas: indexación, clasificación, remodelación, funciones elementales elementales, etc. Todo código numérico residiría en SciPy. Sin embargo, uno de los objetivos importantes de NumPy es la compatibilidad, por lo que NumPy trata de 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 apropiadamente a SciPy. En cualquier caso, SciPy contiene más versiones completas de los módulos de álgebra lineal, así como muchos otros algoritmos numéricos. Si está haciendo informática científica con python, probablemente debería instalar tanto NumPy como SciPy. La mayoría de las características nuevas pertenecen a SciPy en lugar de NumPy.
Eso explica por qué scipy.linalg.solve
ofrece algunas características adicionales sobre numpy.linalg.solve
.
No vi la respuesta de SethMMorton a la pregunta relacionada
De las 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 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.
Hay un breve comentario al final de la introducción a la documentación de SciPy :
Otro comando útil es la
source
. Cuando se le asigna una función escrita en Python como argumento, imprime una lista del código fuente para esa función. Esto puede ser útil para aprender sobre un algoritmo o para entender exactamente qué está haciendo 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 le permitirá a alguien con suficiente conocimiento de todos los paquetes involucrados distinguir exactamente cuáles son las diferencias entre algunas funciones scipy y numpy (no me ayudó en absoluto con la pregunta log10). Definitivamente no tengo ese conocimiento pero la source
indica que scipy.linalg.solve
y numpy.linalg.solve
interactúan 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í, por favor hágamelo saber.
La última vez que lo revisé, el método __init__ de __init__
ejecuta un
from numpy import *
de modo que todo el espacio de nombres numpy se incluye en scipy cuando se importa el módulo scipy.
El comportamiento de log10
que está describiendo es interesante, porque ambas versiones provienen de numpy. Uno es ufunc
, el otro es una función numpy.lib
. ¿Por qué scipy es preferir la función de biblioteca en lugar de ufunc
, no sé de la cabeza.
EDIT: De hecho, puedo responder a la pregunta log10
. Mirando en el método __init__ de __init__
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 función log10
que obtienes en scipy proviene de 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 el módulo superpone el número base de ufuncs 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 algún lugar.