Pythonライブラリ入門

Pythonプログラミングにおいては,アルゴリズムを直接記述する方法も可能であるが,ライブラリと呼ばれる特定の機能をまとめた再利用可能なモジュール群が提供されている. これらを用いることにより,自分でアルゴリズム記述やそのデバッグをせずとも,プログラムを効率的に開発することができる. このなかでも,numpy, scipy, matplotlibといった外部ライブラリは,科学技術計算において幅広く用いられている. NumPyは高速な配列操作と線形代数,SciPyは信号処理などの計算機能,Matplotlib はグラフ作成やデータの可視化を簡単にする. Pythonのライブラリは組み合わせて使用され,データ処理,画像処理,可視化,制御,シミュレーション,機械学習など,工学の幅広い分野で活用されている.

参考:Pythonの基本については,情報処理実習1のPython入門を参照.
注:情報処理教室のPCでは,このページのサンプルプログラムをそのまま実行することができる.
一方,USBメモリにインストールした推奨開発環境(cprog20)には,Python本体やライブラリ類がインストールされていないため,大学の情報処理教室や生田仮想デスクトップPC上で実行する場合は問題ないが,自分のPC,Macなどで実行する場合は,Pythonおよびライブラリの適切なインストールが必要である.
具体的には,Python公式サイトからOSに適したPython本体をダウンロード・インストールし,さらにpipコマンドなどを用いて各種ライブラリを追加インストールする必要がある.
(ヒント:pip install numpy, pip install scipy, pip install matplotlib など)

代表的なライブラリ

以下に代表的なライブラリへのリンクを記すので,必要に応じてドキュメント,リファレンスマニュアル,検索を用いて,各自で調べて取り組んでみよう.

NumPy

NumPyは数値計算の基盤となるライブラリで,多次元配列(ndarray)を中心として,多くの数学関数や線形代数,統計計算などを提供する. 配列の演算がC言語と同等の速度で最適化されており,Python標準のリストと比べて高速に計算できる. 科学計算や機械学習,データ解析において必須の基礎ライブラリである.

SciPy

SciPyはNumPyをベースとした科学技術計算用ライブラリで,数値積分,微分方程式,信号処理,統計解析など,高度な数学処理を行うことができる. 各分野ごとにサブモジュールが分かれており,複雑な数値計算を簡潔なコードで記述できる. 研究・開発用途で利用される場面が多く,シミュレーションやデータ解析のツールとして利用されている.

Matplotlib

MatplotlibはPythonでグラフや図を描画するための可視化ライブラリである. 折れ線グラフ,散布図,ヒストグラム,等値面図など多様な図を作成できる. 軸ラベルやタイトル,凡例,色・線のスタイルなど細かい設定が可能であり,再利用可能な形で保存しておくことができる. NumPyと組み合わせてデータを直接可視化できるため,データの分析結果や,シミュレーション・実験結果の表現に最適である. また,グラフの画面表示だけでなく,ファイルへの保存も簡単にでき,実験レポートや論文の図表作成まで幅広く利用されている.


参考:機械学習のためのライブラリ

Pythonでは,機械学習のための様々なフレームワークが提供されており,現状,機械学習開発の標準言語となっている. PyTorch と Tensorflow が2大勢力である.

Python外部ライブラリの利用法

Pythonには標準ライブラリと外部ライブラリが存在する.

標準ライブラリはPythonに最初から組み込まれており,追加インストール不要で利用できる. たとえば,画面表示を行うprintや,文字列操作や日時計算に用いるdatetime,数学計算用のmathが該当する.

外部ライブラリは標準ではインストールされておらず,pipコマンドなどで追加インストールする必要がある.
標準ライブラリは基本的機能を補完するものであり,外部モジュールは特定分野の高度な処理を効率的に実現できる点で異なる.

ライブラリを利用するためには,ソースコードの先頭に以下のいずれかの宣言を記述する.

import numpy
import numpy as np

import文はモジュールを読み込むための構文である.
例えばimport mathとすると,math.sqrt()のようにモジュール名を接頭辞として関数を呼び出す必要がある.
一方,asを用いるとモジュールに別名を付けられる. 例えばimport numpy as npと書くと,numpy.array()ではなくnp.array()と短縮して利用できる. asを使うことでコードの可読性や入力の手間を減らせる利点がある.

import numpy

numpy.array([1,2,3])
import numpy as np

np.array([1,2,3])

ライブラリを利用したプログラム例

例1:NumPyによる配列演算

一次元配列 x,サイズ(=要素数) 100 として,このなかに 0 から 2π までの値を等間隔に生成し,この配列に対してy = sin(x) を計算して最初の5つの値を表示せよ.

NumPyの linspace範囲を均等に分割した配列を作り,np.sin で要素ごとの正弦を計算する.
NumPyの関数は配列全体に一度に作用するため,for ループなどを記述する必要がない.

Pythonソースコード
import numpy as np

x = np.linspace(0, 2 * np.pi, 100)  # x はnumpy配列,np.piは円周率
y = np.sin(x)

print('x=', x)
print('y=', y)

練習問題

  1. 上記のPythonのプログラムを実行して,出力を確認しよう.
  2. 配列zに,余弦(cos) の値を格納して,同様に表示してみよう.
  3. 配列x,y, zについて,最初の5つの要素のみを表示するようにしてみよう.

    ヒント:配列xの最初の5要素は,x[:5] とかける.for文を使用しても良い.
    実行例
    
    x= [0.         0.06346652 0.12693304 0.19039955 0.25386607]
    y= ...
    z= ...
    

比較のために,同様の計算処理を行うC言語ソースコードを以下に示す.
実行して,出力を比較してみよう.

C言語ソースコード
#include <stdio.h>
#include <math.h>

const double pi = 2.0*asin(1.0);

int main(void)
{
    int i;
    const int N=100;
    double x[N];   // array
    double y[N];   // array

    //  set x
    for(i=0; i<N; i++) {
        x[i] = 2.0*pi*i/(N-1);
    }

    //  set y
    for(i=0; i<N; i++) {
        y[i] = sin(x[i]);
    }

    // show x on display
    printf("x=");
    for(i=0; i<N; i++) {
        printf("%.10lf ", x[i]);
    }
    printf("\n");

    // show y on display
    printf("y=");
    for(i=0; i<N; i++) {
        printf("%.10lf ", y[i]);
    }
    printf("\n");

    return 0;
}

例2:NumPyによる行列計算

行列の積

NumPyでは,行列や多次元配列の定義も容易である. 以下の 2×2 行列 A, B を NumPy 配列として定義し,行列積 AB を求めてみよう.

C言語では,定数による配列の初期化を{}で表すが,Pythonでは[]を用いる.

A = [[2, 1], [-1, 3]]
B = [[0, 4], [5, -2]]

二次元配列を np.array で定義し,行列積は np.dot あるいは @ 演算子で求められる.

import numpy as np

A = np.array([[2, 1],
              [-1, 3]])
B = np.array([[0, 4],
              [5, -2]])

C = A @ B   # 行列の積

print('A=\n', A, '\n')
print('B=\n', B, '\n')
print('C=\n', C, '\n')

練習問題

  1. 上記プログラムを実行して,計算結果を確認しよう.可能であれば,行列積を手計算してみよう.
  2. 行列の値を変更して,結果を確認してみよう.
  3. 積の順序を交換して,結果を確認してみよう.

行列とベクトルの積

行列とベクトルの積は,いろいろな分野で必須となる計算である. この計算についても,forなどの繰り返し文を記述することなく計算することができる.
(内部的にはもちろん反復処理が行われている.多くのライブラリはC言語で書かれており,計算速度も最適化されている.)

import numpy as np
 
A = np.array([[4, 1],
              [1, -2]])
v = np.array([2,-1])
 
print('A=\n', A, '\n')
print('v=\n', v, '\n')

w = A @ v   # 行列とベクトルの積
print('w=\n', w, '\n')

練習問題

  1. 上記プログラムを実行して,計算結果を確認しよう.可能であれば,積を手計算してみよう.
  2. 行列の値を変更して,結果を確認してみよう.

逆行列

逆行列は,NumPyのlinalg.inv() で容易に求めることができる.

import numpy as np

A = np.array([[4, 1],
              [1, -2]])
v = np.array([2,-1])
 
print('A=\n', A, '\n')
print('v=\n', v, '\n')
 
w = A @ v   # 行列 A とベクトル v の積
print('w=\n', w, '\n')
 
A_inv = np.linalg.inv(A)  # A の逆行列
print('A_inv=\n', A_inv, '\n')

print('A*A_inv=\n', A@A_inv, '\n')  # 行列 A と,その逆行列 A_inv との積

# Aの逆行列を使って w から v を計算
v_reconst = A_inv @ w
print('v_reconst=', v_reconst, '\n')
print('v (original)=', v, '\n')

練習問題

  1. 上記プログラムを実行して,計算結果を確認しよう.
  2. 行列の値を変更して,結果を確認してみよう.

例3:Matplotlibによる折れ線グラフの描画

Matplotlibは,折れ線グラフや散布図,等値面図などレポートや論文に必要な図表の作成を簡単に行うことができる.
ファイルの読み込みや,データ加工,表示されるグラフの種類や細かい体裁の設定,ファイル出力まで,すべてソースファイル内で制御することができるため,一度Pythonのソースコードを作成しておけば,次回以降は同様の品質のグラフを大量に生成することができる.

ここでは,x, y = sin(x) を折れ線グラフとして描画してみよう.横軸に「x」,縦軸に「sin(x)」,適切なタイトルもつけよう.

Matplotlibの基本描画は plt.plot である.
軸ラベルやタイトルは plt.xlabel などで設定できる.

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
z = np.cos(x)

plt.plot(x, y)
plt.plot(x, z)

plt.xlabel('x')
plt.ylabel('sin(x), cos(x)')
plt.title('sinusoidal waves')

# グラフの保存
plt.savefig('waves.jpeg')

plt.show()

練習問題

  1. 上記プログラムを実行して,計算結果を確認しよう.出力されたファイルも開いて確認しよう.

例4:散布図と回帰直線

データ: x = [0,1,2,3,4], y = [1,2,2,3,4] を散布図として描画してみよう.
次に,(最小二乗法による)線形近似直線を求め,同じ図に重ねて描画してみよう.

まず,散布図を描画してみよう.

import numpy as np
import matplotlib.pyplot as plt
 
x = np.array([0, 1, 2, 3, 4])
y = np.array([1, 2, 2, 3, 4])
 
plt.scatter(x, y)
 
plt.xlabel('x')
plt.ylabel('y')
plt.title('Scatter plot')
plt.show()

次に,NumPyの polyfitで1次関数近似の係数を求める.
Pythonでは,戻り値が複数でもOK

import numpy as np

x = np.array([0, 1, 2, 3, 4])
y = np.array([1, 2, 2, 3, 4])

coeff = np.polyfit(x, y, 1)  # 1次近似の係数を計算
print('coeff=', coeff)       # 係数を表示

実行結果:
[0.7 1. ]

polyfit で求めた係数から,poly1d で関数化する.
最終的に,以下のように散布図と直線を同じグラフ上に描画する.

import numpy as np
import matplotlib.pyplot as plt

x = np.array([0, 1, 2, 3, 4])
y = np.array([1, 2, 2, 3, 4])

plt.scatter(x, y)   # 散布図を表示

coeff = np.polyfit(x, y, 1)  # 1次近似の係数を計算
print('coeff=', coeff)       # 係数を表示
linear = np.poly1d(coeff)    # 係数から多項式の関数を生成
plt.plot(x, linear(x))       # 近似直線を追加

plt.xlabel('x')
plt.ylabel('y')
plt.title('Scatter plot and regression')
plt.show()

練習問題

  1. 上記プログラムを実行して,計算結果を確認しよう.出力されたファイルも開いて確認しよう.
  2. np.polyfit のリファレンスマニュアルを調べ,近似の次数を2次,3次に変更してみよう.

実習課題

Pythonソースファイルおよび必要に応じてグラフのファイルを提出せよ.

1.リストを使った計算

ある実験で,センサーから得られた以下のデータがあるとする.
data = [0.1, 0.5, 0.02, 0.3, 0.8, 0.05, 0.4, 0.9, 0.07, 0.2]

このリストを使って,次の値を計算して表示せよ.
自分でアルゴリズムを記述してもよいし,Pythonの公式ドキュメントから適切な関数を探して使用してもよい.

  1. 値の合計 (sum)
  2. 値の平均値 (average)
  3. 最小値と最大値 (min, max)
  4. 「値が 0.1 未満」のデータだけを取り出して新しいリストを作成し,その個数と内容を表示
実行例:

合計: 3.34000000000
平均: 0.334
最小値: 0.02
最大値: 0.9
0.1 未満の値 (3 個): [0.02, 0.05, 0.07]

2.グラフデータの可視化

以下のような xy データがある.
x = [0, 1, 2, 3, 4, 5]
y = [1, 1.5, 1.8, 2.5, 2.2, 3.0]

このデータを使って,以下を行うプログラムを作成せよ.
必要な関数などは,matplotlibのWebサイトなどを用いて各自で調べてみよう.
例:matplotlib.pyplotのリファレンス

以下,結果の出力例である.プロットの形や色,線の種類などを自由に変えてもよい.

data plot
図:plot の例