SciPyは、独自のネームスペースでNumPyの機能のほとんど(すべてではない[1])を提供するようです。つまり、numpy.foo
という名前の関数がある場合、ほぼ確実にscipy.foo
があります。ほとんどの場合、2つはまったく同じように見え、多くの場合、同じ関数オブジェクトを指しています。
時々、それらは異なっています。最近出てきた例を挙げると:
numpy.log10
は、負の引数に対してNaNを返す func です。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を使用してテスト済み。
前回チェックしたとき、scipy __init__
メソッドは
from numpy import *
scipyモジュールがインポートされると、numpy名前空間全体がscipyに含まれるようになります。
bothバージョンはnumpyから来ているため、説明しているlog10
の動作は興味深いものです。 1つはufunc
、もう1つは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.
"""
モジュールは、sqrt
、log
、log2
、logn
、log10
、power
、arccos
、arcsin
、およびarctanh
のベースnumpy ufuncsをオーバーレイしているようです。それはあなたが見ている振る舞いを説明しています。そのように行われる基本的な設計上の理由は、おそらくどこかのメーリングリストの投稿に埋もれているでしょう。
SciPyリファレンスガイドから:
...すべてのNumpy関数は
scipy
名前空間に含まれているため、これらすべての関数はNumpyを追加インポートせずに使用できます。
意図的に例外を見つけたとしても、ユーザーはscipy
名前空間とnumpy
名前空間の違いを知る必要はありません。
SciPy FAQ からわかるように、NumPyの一部の関数は歴史的な理由でここにありますが、SciPyにのみあるべきです:
NumPyとSciPyの違いは何ですか?
理想的な世界では、NumPyには配列データ型と最も基本的な操作(インデックス作成、並べ替え、再形成、基本的な要素ごとの関数など)しか含まれていません。すべての数値コードはSciPyにあります。ただし、NumPyの重要な目標の1つは互換性であるため、NumPyは前任者のいずれかによってサポートされているすべての機能を保持しようとします。したがって、NumPyには線形代数関数が含まれていますが、これらはより適切にSciPyに属します。いずれにせよ、SciPyには、他の多くの数値アルゴリズムと同様に、線形代数モジュールのより完全な機能を備えたバージョンが含まれています。 Pythonで科学計算を行っている場合は、おそらくNumPyとSciPyの両方をインストールする必要があります。ほとんどの新機能は、NumPyではなくSciPyに属します。
scipy.linalg.solve
がnumpy.linalg.solve
を超えるいくつかの追加機能を提供する理由を説明しています。
関連する質問 に対するSethMMortonの答えが見つかりませんでした
SciPyの紹介 ドキュメントの最後に短いコメントがあります:
別の便利なコマンドは
source
です。 Pythonで記述された関数を引数として指定すると、その関数のソースコードのリストが出力されます。これは、アルゴリズムについて学習したり、引数で関数が何をしているのかを正確に理解するのに役立ちます。また、モジュールまたはパッケージの名前空間を調べるために使用できるPythonコマンドディレクトリも忘れないでください。
これにより、関係するすべてのパッケージについて十分な知識を持っている人が、somescipy関数とnumpy関数の違いを正確に区別できるようになると思いますtは、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))
これも私の最初の投稿なので、ここで何かを変更する必要がある場合はお知らせください。
ウィキペディアから( http://en.wikipedia.org/wiki/NumPy#History ):
数値コードは、Numarrayの新しい機能を実装するのに十分な保守性と柔軟性を実現するように適合されました。この新しいプロジェクトはSciPyの一部でした。配列オブジェクトを取得するためだけにパッケージ全体をインストールするのを避けるため、この新しいパッケージは分離され、NumPyと呼ばれました。
scipy
はnumpy
に依存し、多くのnumpy
関数を名前空間にインポートして便利にします。
Linalgパッケージについて-scipy関数はlapackとblasを呼び出します。これらは、多くのプラットフォームで高度に最適化されたバージョンで利用可能で、特に適度に大きい密行列での操作に対して非常に優れたパフォーマンスを提供します。一方、それらはコンパイルが容易なライブラリではないため、完全なパフォーマンスを得るには、Fortranコンパイラと多くのプラットフォーム固有の調整が必要です。したがって、numpyは、多くの目的に十分対応できる多くの一般的な線形代数関数の簡単な実装を提供します。
SciPy FAQ 複製の説明は主に後方互換性のためであることに加えて、 NumPy documentation でさらに明確にされています
オプションでSciPy加速ルーチン(numpy.dual)
Scipyによって加速される可能性のある機能のエイリアス。
SciPyを構築して、FFT、線形代数、および特殊関数用の高速化または改善されたライブラリを使用できます。このモジュールにより、開発者はSciPyが利用可能なときにこれらの高速化された機能を透過的にサポートできますが、NumPyのみをインストールしたユーザーを引き続きサポートできます。
簡潔にするために、これらは次のとおりです。
また、 SciPyチュートリアル から:
SciPyの最上位には、NumPyおよびnumpy.lib.scimathの関数も含まれています。ただし、代わりにNumPyモジュールから直接使用することをお勧めします。
そのため、新しいアプリケーションでは、SciPyの最上位で複製される配列操作のNumPyバージョンを優先する必要があります。上記のドメインについては、SciPyのドメインを優先し、必要に応じてNumPyの下位互換性を確認する必要があります。
私の個人的な経験では、私が使用する配列関数のほとんどはNumPyの最上位にあります(random
を除く)。ただし、ドメイン固有のルーチンはすべてSciPyのサブパッケージに存在するため、私はSciPyのトップレベルのものをほとんど使用しません。
「 定量的経済学 」に関する講義から
SciPyは、配列データ型と関連機能を使用して、NumPyの上に構築されるさまざまなツールを含むパッケージです
実際、SciPyをインポートすると、SciPy初期化ファイルからわかるように、NumPyも取得されます。
# 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で役立つのは、そのサブパッケージの機能です