Związek między SciPy a NumPy

253

Wydaje się, że SciPy zapewnia większość (ale nie wszystkie [1]) funkcji NumPy we własnej przestrzeni nazw. Innymi słowy, jeśli istnieje funkcja o nazwie numpy.foo, prawie na pewno istnieje scipy.foo. Przez większość czasu oba wydają się być dokładnie takie same, często nawet wskazują na ten sam obiekt funkcyjny.

Czasami są inni. Aby podać przykład, który pojawił się niedawno:

  • numpy.log10jest ufunc, który zwraca NaN dla negatywnych argumentów;
  • scipy.log10 zwraca złożone wartości dla argumentów ujemnych i nie wydaje się być ufunc.

To samo można powiedzieć o log, log2a logn, ale nie o log1p[2].

Z drugiej strony numpy.expi scipy.expwydają się być różnymi nazwami dla tego samego ufunc. Dotyczy to również scipy.log1pi numpy.log1p.

Innym przykładem jest numpy.linalg.solvevs scipy.linalg.solve. Są podobne, ale ta ostatnia oferuje kilka dodatkowych funkcji w stosunku do pierwszej.

Dlaczego pozorne powielanie? Jeśli ma to być hurtowy import numpydo scipyprzestrzeni nazw, dlaczego subtelne różnice w zachowaniu i brakujące funkcje? Czy istnieje jakaś nadrzędna logika, która pomogłaby usunąć zamieszanie?

[1] numpy.min, numpy.max, numpy.absi kilka innych nie mają odpowiedników w scipyprzestrzeni nazw.

[2] Testowane przy użyciu NumPy 1.5.1 i SciPy 0.9.0rc2.

NPE
źródło
7
Czytam w odpowiedziach, że all of those functions are available without additionally importing Numpyponieważ the intention is for users not to have to know the distinction between the scipy and numpy namespaces. Teraz się zastanawiam, bo śledzę posty o numpy i trochę chropowaty i sam go używam. I prawie zawsze widzę, że numpy jest importowane osobno (jako np.). Więc zawiedli?
joris
8
istnieją pewne różnice między scipy a numpy w FFT, raz ugryzł mnie problem, który ostatecznie wyśledził wersję sffy i numpy w rfft zdefiniowaną inaczej
wim
1
FFT SciPy i NumPy są różne. SciPy korzysta z biblioteki Fortran FFTPACK, stąd nazwa scipy.fftpack. NumPy używa biblioteki C o nazwie fftpack_lite; ma mniej funkcji i obsługuje tylko podwójną precyzję w NumPy. Enthought inc. załatał ich numpy.fft, aby używać Intel MKL dla FFT zamiast fftpack_lite.
Sturla Molden
7
NumPy pierwotnie nazywał się scipy.core. NumPy i SciPy to ściśle powiązane projekty. Głównym powodem separacji jest upewnienie się, że biblioteka macierzy (NumPy) jest uboga i wredna, ponieważ większość SciPy nie zawsze jest potrzebna. Ponadto naukowcy podjęli decyzję o wycofaniu pakietów tablic numerycznych (MIT) i numarray (NASA) na korzyść scipy.core, dlatego otrzymali nazwę NumPy. SciPy wciąż nie osiągnął 1.0, podczas gdy NumPy jest obecnie wydany jako 1.8.1. NumPy ma pewne udogodnienia dla FFT i algebry liniowej, ale nie tak rozbudowane jak SciPy.
Sturla Molden
@SturlaMolden dobrze wiedzieć o Enthought, czy wiesz, czy Anaconda optymalizuje oba, czy po prostu numpy?
dashy

Odpowiedzi:

138

Ostatnim razem, gdy to sprawdziłem, __init__metoda scipy wykonuje a

from numpy import *

dzięki czemu cała przestrzeń nazw numpy jest dołączana do scipy podczas importowania modułu scipy.

log10Zachowanie opisujesz jest interesujący, ponieważ obydwie wersje pochodzą z numpy. Jedna to ufuncdruga, a druga to numpy.libfunkcja. Dlaczego scipy woli bibliotekę od tej ufunc, nie wiem od samego początku.


EDYCJA: W rzeczywistości mogę odpowiedzieć na log10pytanie. Patrząc na __init__metodę scipy , widzę to:

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

log10Funkcja pojawi się w scipy pochodzi numpy.lib.scimath. Patrząc na ten kod, mówi:

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

Wydaje się, że nakładki Moduł ufuncs baza NumPy na sqrt, log, log2, logn, log10, power, arccos, arcsin, i arctanh. To wyjaśnia zachowanie, które widzisz. Podstawowy powód, dla którego tak się to robi, jest prawdopodobnie ukryty gdzieś na liście mailingowej.

szpony
źródło
10
Po dłuższej pracy z tymi pakietami mam wrażenie, że o tym myślę: NumPy ma być biblioteką tablic numerycznych, z której może korzystać każdy, kto potrzebuje takiego obiektu w Pythonie. SciPy ma być biblioteką dla naukowców / inżynierów, więc ma na celu bardziej rygorystyczną matematykę teoretyczną (a zatem zawiera wersję liczbową log10 i tym podobne). Główne zamieszanie wynika z faktu, że NumPy zachowuje wiele starych podmodułów (które powinny były zostać wprowadzone w Scipy), które zostały uwzględnione w czasie, gdy rozgraniczenie między SciPy / NumPy nie było tak jasne, jak jest dzisiaj.
PhilMacKay
@PhilMacKay Cześć Phil, przeczytałem ten i twój inny post dotyczący tego numpy / scipy pytania z 2013 roku. Moje pytanie brzmi, czy twoja opinia jest nadal aktualna, jak stwierdzono dobrze w komentarzu powyżej? widzę, że na plakacie jest kilka ekwiwalentów w scipy i podaje przykłady abs, max i min jako przykłady, ale rozumiem, że abs jest tylko aliasem dla numpy.absolute i istnieje scipy.absolute, scipy.maximum i scipy .minimum. Tak więc, według twojego doświadczenia, czy kiedykolwiek musiałeś importować numpy, jeśli już potrzebujesz scipy?
Dan Boschen,
@PhilMacKay Wygląda na to, że ogólny konsensus polega na użyciu bibliotek podmodułów SciPy do odpowiednich przypadków użycia, a następnie do podstawowych operacji NumPy w celu importowania NumPy konkretnie (zamiast najwyższego poziomu SciPy, który w innym przypadku musiałby zaimportować ). Z jakiegoś powodu inni twierdzą to, podobnie jak sama dokumentacja SciPy, jako lepsza praktyka kodowania i staram się zrozumieć, dlaczego to ma znaczenie. Zakładam, że dzieje się tak, ponieważ jest to kwestia konwencji, a zatem czytelności. Jaka jest twoja obecna opinia?
Dan Boschen,
@ DanBoschen Od listopada 2018 r. Nadal podtrzymuję powyższy komentarz. Importowanie SciPy, gdy potrzebny jest tylko NumPy, może być nieco przesadne. Z drugiej strony NumPy jest importowany po załadowaniu SciPy, więc nie ma potrzeby importowania NumPy oprócz SciPy. Oczywiście istnieją dobre argumenty przemawiające za przestrzeganiem dokumentacji, więc rób to, co najbardziej istotne w twojej sytuacji.
PhilMacKay,
@PhilMacKay Dziękujemy za Twój wkład. Po przemyśleniu, dlaczego sugeruje się importowanie numpy (chociaż wszystko można zrobić w scipy), jest to kwestia konwencji, a zatem czytelności wspólnego kodu. Jeśli cały kod specyficzny dla numpy jest konkretnie powiązany z biblioteką numpy, można go również łatwiej oderwać od powiązania z większą biblioteką scipy, która zawiera o wiele więcej, co nie zawsze może być potrzebne. To powiedziawszy, moim zdaniem (moim własnym podejściem) jest zaimportowanie numpy, a następnie NIE importowanie scipy najwyższego poziomu, ale tylko importowanie scipy subpackages w razie potrzeby.
Dan Boschen
52

Z SciPy Reference Guide:

... wszystkie funkcje Numpy zostały umieszczone w scipy przestrzeni nazw, dzięki czemu wszystkie te funkcje są dostępne bez dodatkowego importowania Numpy.

Chodzi o to, aby użytkownicy nie musieli znać rozróżnienia między przestrzeniami nazw scipyi numpy, chociaż najwyraźniej znalazłeś wyjątek.

John D. Cook
źródło
50

Z SciPy FAQ wynika, że ​​niektóre funkcje NumPy są tutaj ze względów historycznych, podczas gdy powinno być tylko w SciPy:

Jaka jest różnica między NumPy a SciPy?

W idealnym świecie NumPy zawierałby tylko typ danych tablicowych i najbardziej podstawowe operacje: indeksowanie, sortowanie, przekształcanie, podstawowe funkcje elementarne i tak dalej. Cały kod numeryczny znajdowałby się w SciPy. Jednak jednym z ważnych celów NumPy jest kompatybilność, dlatego NumPy stara się zachować wszystkie funkcje obsługiwane przez jednego z jego poprzedników. W ten sposób NumPy zawiera pewne funkcje algebry liniowej, nawet jeśli bardziej poprawnie należą do SciPy. W każdym razie SciPy zawiera bardziej w pełni funkcjonalne wersje modułów algebry liniowej, a także wiele innych algorytmów numerycznych. Jeśli wykonujesz obliczenia naukowe za pomocą Pythona, prawdopodobnie powinieneś zainstalować zarówno NumPy, jak i SciPy. Większość nowych funkcji należy do SciPy, a nie NumPy.

To wyjaśnia, dlaczego scipy.linalg.solveoferuje kilka dodatkowych funkcji numpy.linalg.solve.

Nie widziałem odpowiedzi SethMMorton na powiązane pytanie

PhML
źródło
12

Na końcu wprowadzenia do dokumentacji SciPy znajduje się krótki komentarz :

Innym przydatnym poleceniem jest source. Gdy podano jako argument napisaną funkcję w Pythonie, wypisuje on listę kodu źródłowego dla tej funkcji. Może to być pomocne w poznaniu algorytmu lub zrozumieniu, co funkcja robi z argumentami. Nie zapomnij także o katalogu poleceń Pythona, którego można użyć do przeglądania przestrzeni nazw modułu lub pakietu.

Myślę, że pozwoli to komuś z wystarczającą wiedzą na temat wszystkich zaangażowanych pakietów dokładnie rozróżnić różnice między niektórymi funkcjami scipy i numpy (nie pomogło mi to w przypadku pytania log10). Zdecydowanie nie mam tej wiedzy, ale sourceto wskazuje scipy.linalg.solvei numpy.linalg.solvena różne sposoby wchodzę w interakcję z lapackiem;

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

To także mój pierwszy post, więc jeśli coś tu zmienię, daj mi znać.

dshort
źródło
Podstawowe opakowania są bardzo różne. NumPy używa cienkiej warstwy napisanej w C. SciPy używa warstwy automatycznie generowanej przez f2py. SciPy zawsze łączy się z zewnętrzną biblioteką LAPACK. NumPy używa własnego f2c'd lapack_lite na wypadek, gdyby zewnętrzny LAPACK nie został znaleziony.
Sturla Molden
8

Z Wikipedii ( http://en.wikipedia.org/wiki/NumPy#History ):

Kod numeryczny został dostosowany, aby był łatwiejszy w utrzymaniu i wystarczająco elastyczny, aby zaimplementować nowatorskie funkcje Numarray. Ten nowy projekt był częścią SciPy. Aby uniknąć instalowania całego pakietu tylko w celu uzyskania obiektu tablicy, nowy pakiet został oddzielony i nazwany NumPy.

scipyzależy numpyi importuje wiele numpyfunkcji do przestrzeni nazw dla wygody.

Mu Mind
źródło
4

Jeśli chodzi o pakiet linalg - funkcje scipy będą wywoływać lapack i blas, które są dostępne w wysoce zoptymalizowanych wersjach na wielu platformach i oferują bardzo dobrą wydajność, szczególnie w przypadku operacji na stosunkowo dużych gęstych matrycach. Z drugiej strony nie są łatwymi bibliotekami do kompilacji, wymagającymi kompilatora fortran i wielu poprawek specyficznych dla platformy, aby uzyskać pełną wydajność. Dlatego numpy zapewnia proste implementacje wielu typowych funkcji algebry liniowej, które często są wystarczające do wielu celów.

DaveP
źródło
numpy 1.10 ma fajny moduł dual: „Ten moduł powinien być używany do funkcji zarówno w numpy, jak i scipy, jeśli chcesz używać wersji numpy, jeśli jest dostępna, ale w przeciwnym razie wersja scipy”. Zastosowanie ---from numpy.dual import fft, inv
den
1

Od Wykłady na „ Quantitative Ekonomicznej

SciPy to pakiet zawierający różne narzędzia zbudowane na NumPy, wykorzystujące jego typ danych tablicowych i powiązaną funkcjonalność

W rzeczywistości, gdy importujemy SciPy, otrzymujemy również NumPy, jak widać z pliku inicjującego 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')

Jednak bardziej powszechną i lepszą praktyką jest jawne korzystanie z funkcji NumPy

import numpy as np

a = np.identity(3)

W SciPy przydatna jest funkcjonalność jej podpakietów

  • scipy.optimize, scipy.integrate, scipy.stats itp.
Vlad Bezden
źródło
1
Widzę twój komentarz, że lepiej jest jawnie korzystać z funkcji NumPy i widzę to w innym miejscu, w tym w samouczku SciPy, ale dlaczego ta lepsza praktyka? Wydaje się, że nikt nie odpowiada na to pytanie. Jeśli już importujesz SciPy i zawiera on funkcję NumPy, dlaczego lepiej importować NumPy? Czy to dlatego, że kiedy importujemy podpakiet w SciPy, NIE importujemy najwyższego poziomu, a zatem zamiast robić konkretny import SciPy, powinniśmy po prostu zaimportować Numpy dla tych podstawowych funkcji przetwarzania tablicy?
Dan Boschen,
1

Oprócz SciPy FAQ opisującego powielanie dotyczy głównie wstecznej kompatybilności, wyjaśniono w dokumentacji NumPy, aby powiedzieć, że

Opcjonalnie procedury przyspieszane przez SciPy (numpy.dual)

Aliasy dla funkcji, które mogą być przyspieszane przez Scipy.

SciPy można zbudować tak, aby używał przyspieszonych lub w inny sposób ulepszonych bibliotek dla FFT, algebry liniowej i funkcji specjalnych. Ten moduł pozwala programistom w przejrzysty sposób wspierać te przyspieszone funkcje, gdy SciPy jest dostępny, ale nadal obsługuje użytkowników, którzy zainstalowali tylko NumPy.

Dla zwięzłości są to:

  • Algebra liniowa
  • FFT
  • Zmodyfikowana funkcja Bessela pierwszego rodzaju, rząd 0

Ponadto z samouczka SciPy :

Najwyższy poziom SciPy zawiera również funkcje z NumPy i numpy.lib.scimath. Lepiej jednak użyć ich bezpośrednio z modułu NumPy.

Tak więc, w przypadku nowych aplikacji, powinieneś preferować wersję NumPy operacji tablicowych, które są duplikowane na najwyższym poziomie SciPy. W przypadku domen wymienionych powyżej powinieneś preferować domeny w SciPy i sprawdzić wsteczną zgodność, jeśli to konieczne w NumPy.

Z mojego osobistego doświadczenia wynika, że ​​większość funkcji tablicy, z których korzystam, istnieje na najwyższym poziomie NumPy (oprócz random). Jednak wszystkie procedury specyficzne dla domeny istnieją w podpakcjach SciPy, więc rzadko używam czegokolwiek z najwyższego poziomu SciPy.

jbbiomed
źródło