1.4. NumPy/SciPy

python本体(標準ライブラリー)には、数学/物理に使える関数はほぼ何も定義されていないので、python本体だけでは数値計算はできない。一般的にコードを書くときにはpython本体だけでなく、さまざまなモジュール(module)を必要に応じて追加(インポート, import)していくことになる。数値計算では、NumPyという非常に強力な数値計算モジュールが用意されていて、数学で使える基本的な関数はほんどすべて揃っている。今後講義でコードを書くときは、ほぼ100%、NumPyを使うことになるし、pythonを使っている科学技術計算、機械学習を含むデータサイエンスでは常にNumPyを用いていると思っていい。それほど重要なモジュールである。

SciPyはNumPyを基にしてさらに高度な数値計算が可能なモジュールである。ざっくりいうと上位互換と思っていい。公式に細かい使い方が書かれているので、functionのargumentや「こんな関数ないかな」と調べるときに参考にするよい。公式なので当たり前だがgoogleで検索して出てくる適当なサイトより網羅的にかつ正確に書かれている。

モジュールを取り込むにはimportを使う。以下のように、numpyimportしてnpと省略するところからすべてのコードが始まる。

In [1]:
import numpy as np

 なにも出力されないが、これでnumpyモジュールがimportされた。まずはnpに用意されている初等関数を使ってみる。ほとんどの初等関数はnp.関数名前という形で定義されている。

In [2]:
np.sqrt(2)
Out[2]:
1.4142135623730951
In [3]:
np.cos(0)
Out[3]:
1.0
In [4]:
np.exp(1)
Out[4]:
2.718281828459045

 円周率$\pi$やネイピア数の$e$などの定数も意義されている。

In [5]:
np.pi
Out[5]:
3.141592653589793
In [6]:
np.e
Out[6]:
2.718281828459045

 SciPyでも同様なことができる。

In [7]:
import scipy
print(scipy.pi)
3.141592653589793

 あるいは以下のようにすることもできる。

In [8]:
from scipy import pi
print(pi)
3.141592653589793

 このようにfrom "モジュール名" import "名前"のようにimportすることもできる。その場合はscipy.piではなくpiと書いてもよい。

 複素数はpythonの標準ライブラリーに入っているのでimportせずに使うことができる。ただし、複素数はiではなく、1jで表す。

In [9]:
a = 2 + 3j
a.real
Out[9]:
2.0
In [10]:
a.imag
Out[10]:
3.0

 複素数a実部や虚部をとる場合は、後ろに.realや、.imagをつける。このように.を付けた後ろの部分を属性(attribute)というのだが、どうしてこういう書き方をするのかは、pythonのclassの詳細に関連して説明するので、今のところはそういうものだと思ってもらいたい。

なお、複素数1jの代わりに1iとしてもpythonは理解してくれない。

In [11]:
a = 2 +3i
  File "<ipython-input-11-028d7bd657d0>", line 1
    a = 2 +3i
            ^
SyntaxError: invalid syntax

 理学系の人にとって複素数は$i$だが、工学系の人にとって$i$という文字は電流と混同しやすいので、複素数は$i$の代わりに$j$を使うのがプログラミング以外でも一般的である。

 

 

練習問題

(1.4.1.) オイラーの公式

\begin{equation}
e^{i\theta} = \cos \theta + i \sin \theta
\end{equation}

 が、$\theta = \frac{\pi}{2}$で成り立っていることを確認せよ。

 

(1.4.2.) 虚数単位$i$の$i$乗の主値が実数となるとことを確認せよ。

 

解答例

(1.4.1.) 複素数の$j$を1jではなく、jとしてしまう間違いが多いので注意しよう。

In [12]:
import numpy as np
theta = np.pi/2
print(np.exp(1j*theta))
print(np.cos(theta) + 1j*np.sin(theta))
(6.123233995736766e-17+1j)
(6.123233995736766e-17+1j)

 両辺とも同じ答えになっているが、実部は6.12...e-17となっていて、厳密解である$0$にはなっていない。これは数値計算で必ず問題となる誤差で、詳細については今後取り上げる。

 

(1.4.2.) $i^i$は多価関数なので、無限の数列となる。ただしpytonでそのまま表現すると単純に主値が求まる。

In [13]:
x = 1j**1j
print(x)
(0.20787957635076193+0j)

となって、確かに虚部が$0$になっている。

当サイトのテキスト・画像の無断転載・複製を固く禁じます。

Unauthorized copying and replication of the contents of this site, text and images are strictly prohibited.
© 2019 Go Yusa