こんにちは(@t_kun_kamakiri)。
基本的な内容はこちらのサイトにそってやっていきます。
この記事ではこんな人を対象にしています。
- Pythonを使い始めたけどどう使うかわからない
- 流体の数値計算をはじめて勉強する人
☟前回の記事がまだの人はこちらから
(※Pythonの環境構築ができている方は必要ありません)
前回の記事で環境構築についてはオッケーだと思うので、今回からPythonを使って具体的な数値計算を実践していきたいと思います。
いきなり偏微分方程式を解こうとすると、数値計算の離散化手法でつまづきそうなのでまずは、Pythonのライブラリであるnumpyの使い方を確認するところから始めましょう。
Numpyは数値演算をするためのライブラリ
まずは、簡単にNumpyの使い方を確認しておきましょう。
今やネット上に日本語で多くの情報があるので調べればすぐに使い方を知ることができます。
一応Numpyについての公式ページがあるのでそちらを参考にしてください。
Numpyの基本的な使い方
numpyを使うには、「numpyを使いますよ」という宣言をする必要があります。
1 2 |
#numpyを使いますよという宣言 import numpy |
numpy自身もPythonで書かれたプログラムのライブラリなので、プログラムの実態はどこかにあるはずです。
1 2 3 |
#numpyはどこにあるのかというと、 print(numpy.__file__) |
【結果】
1 |
/usr/local/lib/python3.6/dist-packages/numpy/__init__.py |
変数\(\pi\)を出力
1 2 3 4 5 6 |
import numpy #変数を呼び出す x = numpy.pi print(x) |
【結果】
1 |
3.141592653589793 |
このように変数を呼び出す場合は、()括弧がいらないのですが、次で見るように関数を呼び出す場合は()括弧が必要です。
関数を呼び出す
呼び出す関数は何でも良いのですが、numpyで用意されている「sin関数」を呼び出してみます。
関数を呼び出す場合は()括弧が必要です。引数として値を入れたり入れなかったりしますが、ここでは「sin関数」には値\(x\)を引数にしています。
1 2 3 4 5 6 7 |
#関数を呼び出す x = numpy.pi y = numpy.sin(x) print(x) print(y) |
【結果】
1 2 |
3.141592653589793 1.2246467991473532e-16 |
「\(\sin(\pi)=0\)」なので「0(限りなく0に近い)」という値が返ってきました。
限りなく0に近いのですが、float型だと16~17桁までの範囲しか扱えないので「1.2246467991473532e-16」は誤差の範囲です。
こんな感じでnumpyを使えばめっちゃ楽に数値計算のためのライブラリが使えます。
毎回、「numpy.pi」などと「numpy」と書くのはめんどう
正直毎回、「numpy」と書くのは面倒なので慣例で「np」と書いて省略して使うことにします。
その方法は、冒頭の一文で「import numpy as np」とするだけです。
1 2 3 4 5 6 7 8 9 |
#毎回、「numpy.pi」などと「numpy」と書くのはめんどうなので、 import numpy as np x = np.pi y = np.sin(x) print(x) print(y) |
【結果】
1 2 |
3.141592653589793 1.2246467991473532e-16 |
これでも先ほどと同じ結果を得られるわけです。
では、もう少しnumpyについて見ていきます。
数値計算で空間領域を要素に分割する必要がありますが、numPyで等間隔の配列ndarrayを生成する主要な方法として次の2つを覚えておけば良いでしょう。
- numpy.linspace()
- numpy.arange()
numpy.linspace(始め, 終わり, 要素数)
空間領域の「始め」と「終わり」を指定して、それを何個の要素を生成するかを指定するだけで良いです。
1 2 3 4 5 6 7 |
import numpy as np x = np.linspace(0,5,10) print(x) print(len(x)) print(type(x)) |
【結果】
1 2 3 4 |
[0. 0.55555556 1.11111111 1.66666667 2.22222222 2.77777778 3.33333333 3.88888889 4.44444444 5. ] 10 <class 'numpy.ndarray'> |
numpy.arange(始め,終わり,分割幅)
空間領域の「始め」と「終わり」を指定して、それをどれくらいの幅で要素を生成するかを指定するだけで良いです。
1 2 3 4 5 6 |
import numpy as np x = np.arange(0,10,0.1) print(x) print(len(x)) print(type(x)) |
【結果】
1 2 3 4 5 6 7 8 |
[0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3. 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4. 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5. 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6. 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7. 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 7.9 8. 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9. 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9] 100 <class 'numpy.ndarray'> |
リスト型とnumpy.ndarrayの違い
numpy.linspace()とnumpy.arange()は、ともに「numpy.ndarray」というデータ型になっています。
出力結果だけを見るとリスト型のようになっていますが、リスト型との違いたとえばこちらの記事を参考にしてもらえればと思います。
ここでは、数値計算をする上でとても重要となる違いだけを紹介しておきます。
例えば、リスト同士の足し算を行うと・・・
1 2 3 4 5 |
list_1 = [1,2,3,4,5] list_2 = [1,2,3,4,5] print(list_1 + list_2) |
【結果】
1 |
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5] |
このように「list_1」の要素に「list_2」が追加されただけであることがわかります。
数値計算の際には、\(\boldsymbol{u}_{i}=(u_i,u_j)\)と\(\boldsymbol{u}_{i-1}=(u_{i-1},u_{j-1})\)の足し算は直感的にも\(\boldsymbol{u}_{i}+\boldsymbol{u}_{i-1}=(u_i+u_{i-1},u_ju_{j-1})\)としてほしいのですが、リスト型だと上手くいっていません。
しかし、これがndarrayだと☟こうなります。
1 2 3 4 5 6 7 8 |
import numpy as np ui = np.linspace(0,5,5) ui_1 = np.linspace(0,5,5) print('ui=',ui) print('ui_1= ',ui_1) print('ui + ui_1 = ',ui + ui_1) |
【結果】
1 2 3 |
ui= [0. 1.25 2.5 3.75 5. ] ui_1= [0. 1.25 2.5 3.75 5. ] ui + ui_1 = [ 0. 2.5 5. 7.5 10. ] |
各要素ごとに足し算された結果になっているのがわかりますね。
実に直感的に、演算が行えます。
このように配列の要素ごとで演算が簡単に行えるのでとても便利ですね。
その他numpyには「行列計算」など簡単に行えるメソッドが用意されているのですが、今回の流体の数値計算には使わないので紹介記事を載せる程度にしておきます。
リスト型をnumpy.ndarryにするnumpy.array(リスト)
用意されているデータがリスト型であったとしても、それをnumpy.ndarryに変換することは簡単にできます。
数値計算のためには、numpyを使って計算した方が計算が速いので必ずnumpy.ndarryとして取り扱うようにします。
1 2 3 4 5 6 7 8 9 10 |
import numpy as np list = [0,1,2,3,4,5] x = np.array(list) print(list) print(x) print(len(x)) print(type(list)) print(type(x)) |
【結果】
1 2 3 4 5 |
[0, 1, 2, 3, 4, 5] [0 1 2 3 4 5] 6 <class 'list'> <class 'numpy.ndarray'> |
データの型を見ると「リスト型」から「numpy.ndarry」に変換されているのが確認できますね。
もちろん、np.array( [0,1,2,3,4,5])と書いても良いです。
numpy.ndarryの要素を抽出する
numpy.ndarryで作成したデータの各要素を取り出したい場合についても確認しておきましょう。
まずは以下のようなデータを用意しておきます。
1 2 3 4 5 6 7 8 |
import numpy as np x = np.linspace(0,9,10) y = np.arange(0,10,1) print('x=',x) print('y=',y) |
【結果】
1 2 |
x= [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] y= [0 1 2 3 4 5 6 7 8 9] |
一応、復習のために「np.linspace」と「np.arange」を使ってみます。
では、このデータから各要素を抽出してみます。
要素を1つ抽出する
要素を1つ抽出する場合は「index」を指定することで、indexに対応する要素をひとつ抽出することができます。
1 2 3 4 5 6 |
#要素を抽出 print(x[0]) print(x[1]) print(x[2]) print(x[3]) |
【結果】
1 2 3 4 |
0.0 1.0 2.0 3.0 |
※indexは「0」からスタートしていることに注意しましょう。
複数の要素を抽出する
複数の要素抽出する場合は以下のように記述します。
1 2 3 4 |
#要素を抽出 print(x[1:3]) print(x[:]) |
【結果】
1 2 |
[1. 2.] [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] |
このように、x[1:3]と書けばindex「1から3より前まで」要素を抽出することができます。
「3まで」ではなくて「3より前まで」なので、実際にはindexは「1,2」を選択して要素の値を抽出しているという点に注意する必要があります。
全ての要素を抽出したい場合はx[:]と書くことで、値を全て抽出できます。
最後から何番目の要素からという指定もできる
1 2 |
print(y[-1]) print(y[-2]) |
【結果】
1 2 |
9 8 |
こんな感じで最後から何番目の要素か・・・という指定もできます。
では、最後から複数の要素も抽出できるのでそれを最後に見てみます。
最後から複数の要素も抽出する
1 2 |
print(y[:-1]) print(y[:-2]) |
【結果】
1 2 |
[0 1 2 3 4 5 6 7 8] [0 1 2 3 4 5 6 7] |
注意する点といえば、
x[:-2]と書けばindex「最後から2番目より前」の要素を抽出することができます。
「最後から2まから前の要素」ではなくて「最後から2番目より前まで」なので、実際にはindexは「0,1,2,3,4,5,6,7」を選択して要素の値を抽出しているという点に注意する必要があります。
まとめ
今回はnumpyの基本的な使い方について解説しました。
この2つは数値計算の空間データを作成する際に必ず使うので覚えておきましょう(^^)/
色々なPythonのライブラリの機能を学びすぎても、使わなければ忘れてしまうので最低限学ぶとしたらこれくらいだろうというものを本記事にまとめました。
Pythonの完全初心者は書籍で学ぶとよい
Python自体が不安だという方は、こちらの書籍から勉強しても良いかも知れません。
☟こちらの本がPython初心者が挫折することなく勉強できる本です。
(本記事のようのPython使用環境と異なりますが、とてもわかりやすいので全く問題ありません)
Jupyter notebook(Jupyter lab)を使ってnumpyを勉強するならこちらの参考書がおすすめです。
本記事では、Google Colaboratoryを使っていますが、操作感はJupyter notebook(Jupyter lab)を使っても同じです。
では、また(^^)/