Связь между scipy и numpy

scipy, как представляется, предоставляет большинство (но не всех [1]) функций numpy в своем собственном пространстве имен. Другими словами, если есть функция с именем numpy.foo, то почти наверняка будет scipy.foo. В большинстве случаев они кажутся точно такими же, часто даже указывающими на один и тот же функциональный объект.

Иногда они разные. Чтобы привести пример, который появился недавно:

  • numpy.log10 - ufunc, который возвращает NaN для отрицательных аргументов;
  • scipy.log10 возвращает сложные значения для отрицательных аргументов и не представляется ufunc.

То же самое можно сказать о log, log2 и logn, но не о log1p [2].

С другой стороны, numpy.exp и scipy.exp кажутся разными именами для того же ufunc. Это также относится к scipy.log1p и numpy.log1p.

Другим примером является numpy.linalg.solve vs scipy.linalg.solve. Они похожи, но последний предлагает некоторые дополнительные функции над первым.

Почему очевидное дублирование? Если это предназначено для оптового импорта numpy в пространство имен scipy, почему тонкие различия в поведении и недостающие функции? Есть ли какая-то всеобъемлющая логика, которая поможет устранить путаницу?

[1] numpy.min, numpy.max, numpy.abs, а некоторые другие не имеют аналогов в пространстве имен scipy.

[2] Протестировано с использованием numpy 1.5.1 и scipy 0.9.0rc2.

Ответ 1

В прошлый раз, когда я проверил его, метод scipy __init__ выполняет

from numpy import *

чтобы все пространство имен numpy было включено в scipy, когда импортирован модуль scipy.

Поведение log10, которое вы описываете, интересно, потому что обе версии идут от numpy. Один из них - ufunc, другой - функция numpy.lib. Почему scipy предпочитает библиотечную функцию над ufunc, я не знаю, что у меня на голове.


EDIT: На самом деле я могу ответить на вопрос 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 на sqrt, log, log2, logn, log10, power, arccos, arcsin и arctanh. Это объясняет поведение, которое вы видите. Основная причина, по которой это делается, вероятно, похожа на место где-то в почтовом списке.

Ответ 2

Из справочного руководства SciPy:

... все функции Numpy имеют был включен в scipyпространства имен, чтобы все эти функции доступны без дополнительно импортируя Numpy.

Цель состоит в том, чтобы пользователи не должны были знать различие между пространствами имен scipy и numpy, хотя, видимо, вы нашли исключение.

Ответ 3

Похоже на scipy часто задаваемые вопросы что некоторые функции из numpy здесь по историческим причинам, в то время как только в scipy:

В чем разница между NumPy и SciPy?

В идеальном мире NumPy не содержит ничего, кроме типа данных массива и самые основные операции: индексирование, сортировка, переформатирование, базовый элементарных функций и т.д. Весь цифровой код будет находиться в SciPy. Однако одной из важных целей NumPys является совместимость, поэтому NumPy пытается сохранить все функции, поддерживаемые одним из его предшественников. таким образом NumPy содержит некоторые линейные функции алгебры, хотя они больше должным образом принадлежат SciPy. В любом случае SciPy содержит более полнофункциональные версии модулей линейной алгебры, а также многие другие численные алгоритмы. Если вы занимаетесь научными вычислениями с помощью python, вы должны вероятно, установите NumPy и SciPy. Большинство новых функций принадлежат SciPy а не NumPy.

Это объясняет, почему scipy.linalg.solve предлагает некоторые дополнительные функции numpy.linalg.solve.

EDIT:

Я не видел ответа SethMMorton на вопрос

Ответ 4

В конце документа в документации SciPy есть короткий комментарий:

Другая полезная команда - source. Когда задана функция, написанная на Python в качестве аргумента, она выводит список исходного кода для этой функции. Это может быть полезно для изучения алгоритма или понимания того, что функция используя свои аргументы. Также не забывайте о директории команды Python, которая может быть используется для просмотра пространства имен модуля или пакета.

Я думаю, что это позволит кому-то, у кого достаточно знаний обо всех пакетах, разобрать, какие именно различия между некоторыми scipy и numpy функциями (это не помогло мне с вопросом log10 вообще). Я определенно не знаю этого знания, но source указывает, что scipy.linalg.solve и numpy.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))

Это также мой первый пост, поэтому, если мне что-то изменить, пожалуйста, дайте мне знать.

Ответ 5

Из Википедии (http://en.wikipedia.org/wiki/NumPy#History):

Цифровой код был адаптирован для он более удобен и гибкий достаточно для реализации новых функций из Numarray. Этот новый проект был частью SciPy. Чтобы избежать установки целого пакет, чтобы получить объект массива, этот новый пакет был отделен и называется NumPy.

scipy зависит от numpy и импортирует многие функции numpy в свое пространство имен для удобства.

Ответ 6

Что касается пакета linalg - функции scipy будут вызывать lapack и blas, которые доступны в высоко оптимизированных версиях на многих платформах и обеспечивают очень хорошую производительность, особенно для операций с достаточно большими плотными матрицами. С другой стороны, им нелегко собирать библиотеки для компиляции, требуя компилятора fortran и многих теневых настроек платформы, чтобы получить полную производительность. Поэтому numpy обеспечивает простые реализации многих общих функций линейной алгебры, которые часто достаточно хороши для многих целей.

Ответ 7

В дополнение к часто задаваемые вопросы по SciPy, описывающие дублирование, в основном, для обратной совместимости, это дополнительно разъясняется в NumPy docs, чтобы сказать, что

Необязательно подпрограммы ускоренного ускорения (numpy.dual)

Псевдонимы для функций, которые могут быть ускорены Scipy.

Scipy может быть создан для использования ускоренных или улучшенных библиотек для БПФ, линейной алгебры и специальных функций. Этот модуль позволяет разработчикам прозрачно поддерживать эти ускоренные функции, когда scipy доступен, но по-прежнему поддерживает пользователей, которые только установили Numpy.

Для краткости это:

  • Линейная алгебра
  • FFT
  • Модифицированная функция Бесселя первого рода, порядок 0

Кроме того, из SciPy Tutorial:

Верхний уровень scipy также содержит функции от numpy и numpy.lib.scimath. Однако лучше использовать их непосредственно из numpy.

Итак, для новых приложений вам следует предпочесть версию NumPy для операций с массивами, которые дублируются на верхнем уровне SciPy. Для доменов, перечисленных выше, вы должны предпочесть функции в SciPy и проверить обратную совместимость, если это необходимо в NumPy.

В моем личном опыте большинство функций массива, которые я использую, существуют на верхнем уровне NumPy (кроме random). Тем не менее, все подпрограммы, относящиеся к домену, существуют в подпакетах SciPy, поэтому я редко использую что-либо из верхнего уровня SciPy.

Ответ 8

Из лекций по 'Количественная экономика'

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 и т.д.