概要
matplotlibを使って式の条件を満たす領域を図示する方法です。
「ゼロから作るDeep Learning」でパーセプトロンの挙動について学ぶ際、
入力と出力の関係を領域として図示してみたいと思ったので試しました。
また、SymPyを使って式の内容を表示させることもやってみました。
実行環境
- Windows10 Pro 64bit (Dockerのホストとして用いています)
- Dockerイメージ python:3.8
- Debian GNU/Linux (version 10.10)
- python 3.8.11
- numpy 1.19.5
- matplotlib 3.4.2
- sympy 1.8
方法
matplotlibによる領域の図示
まずはmatplotlibを使った領域の図示のやり方を説明します。
必要なライブラリをインポートします。
import numpy as np
import matplotlib.pyplot as plt
今回は以下の関数の領域を図示しようと思います。
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
def OR(x1, x2):
x = np.array([x1, x2])
w = np.array([0.7, 0.7])
b = -0.4
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
def NAND(x1, x2):
x = np.array([x1, x2])
w = np.array([-0.5, -0.5])
b = 0.7
tmp = np.sum(w * x) + b
if tmp <= 0:
return 0
else:
return 1
def XOR(x1, x2):
s1 = NAND(x1, x2)
s2 = OR(x1, x2)
return AND(s1, s2)
領域の図示にはmatplotlibのcontourf関数を使います。
そのために、まず格子点を準備します。
(領域(等高線)の図示について詳しくは
matplotlibでの描写 等高線プロットの基礎をわかりやすく説明してみた - Qiita
が分かりやすくまとまっています。)
# xとyの最大・最小値を設定
xmin, xmax = 0, 1
ymin, ymax = 0, 1
# 領域を図示するための格子点を作成
x_arr = np.linspace(xmin, xmax, 101)
y_arr = np.linspace(ymin, ymax, 101)
xx, yy = np.meshgrid(x_arr, y_arr)
次に、格子点を直接代入できるようにするために、
最初に作成した関数をユニバーサル関数化します。
# パーセプトロンの関数をユニバーサル関数化
v_AND = np.vectorize(lambda x1, x2 : AND(x1, x2))
v_OR = np.vectorize(lambda x1, x2 : OR(x1, x2))
v_NAND = np.vectorize(lambda x1, x2 : NAND(x1, x2))
v_XOR = np.vectorize(lambda x1, x2 : XOR(x1, x2))
これで準備は完了です。
plt.contourf()
を使って領域を図示します。
# 軸の目盛りの間隔を設定
tick_interval = 0.1
# ANDの領域を図示
plt.contourf(xx, yy, v_AND(xx, yy), cmap="Blues")
# 図の表示に関する設定
plt.grid() # グリッド線を表示
plt.colorbar() # カラーバーを表示
plt.xlim(xmin, xmax) # x軸の表示範囲を設定
plt.ylim(ymin, ymax) # y軸の表示範囲を設定
plt.xticks(np.arange(xmin, xmax + 0.01, tick_interval)) # x軸の目盛りを設定
plt.yticks(np.arange(ymin, ymax + 0.01, tick_interval)) # y軸の目盛りを設定
plt.xlabel("x1") # 横軸の名前を表示
plt.ylabel("x2") # 縦軸の名前を表示
plt.title("AND") # 図のタイトルを表示
plt.show()
横軸がAND()の入力のうちx1を、縦軸がx2を表しており、
水色の領域がAND()の出力が0になる範囲を、紺色の領域が1になる範囲を表しています。
その他の関数についても同様に図示します。
# ORの領域を図示
plt.contourf(xx, yy, v_OR(xx, yy), cmap="Blues")
# 図の表示に関する設定
plt.grid() # グリッド線を表示
plt.colorbar() # カラーバーを表示
plt.xlim(xmin, xmax) # x軸の表示範囲を設定
plt.ylim(ymin, ymax) # y軸の表示範囲を設定
plt.xticks(np.arange(xmin, xmax + 0.01, tick_interval)) # x軸の目盛りを設定
plt.yticks(np.arange(ymin, ymax + 0.01, tick_interval)) # y軸の目盛りを設定
plt.xlabel("x1") # 横軸の名前を表示
plt.ylabel("x2") # 縦軸の名前を表示
plt.title("OR") # 図のタイトルを表示
plt.show()
# NANDの領域を図示
plt.contourf(xx, yy, v_NAND(xx, yy), cmap="Blues")
# 図の表示に関する設定
plt.grid() # グリッド線を表示
plt.colorbar() # カラーバーを表示
plt.xlim(xmin, xmax) # x軸の表示範囲を設定
plt.ylim(ymin, ymax) # y軸の表示範囲を設定
plt.xticks(np.arange(xmin, xmax + 0.01, tick_interval)) # x軸の目盛りを設定
plt.yticks(np.arange(ymin, ymax + 0.01, tick_interval)) # y軸の目盛りを設定
plt.xlabel("x1") # 横軸の名前を表示
plt.ylabel("x2") # 縦軸の名前を表示
plt.title("NAND") # 図のタイトルを表示
plt.show()
# XORの領域を図示
plt.contourf(xx, yy, v_XOR(xx, yy), cmap="Blues")
# 図の表示に関する設定
plt.grid() # グリッド線を表示
plt.colorbar() # カラーバーを表示
plt.xlim(xmin, xmax) # x軸の表示範囲を設定
plt.ylim(ymin, ymax) # y軸の表示範囲を設定
plt.xticks(np.arange(xmin, xmax + 0.01, tick_interval)) # x軸の目盛りを設定
plt.yticks(np.arange(ymin, ymax + 0.01, tick_interval)) # y軸の目盛りを設定
plt.xlabel("x1") # 横軸の名前を表示
plt.ylabel("x2") # 縦軸の名前を表示
plt.title("XOR") # 図のタイトルを表示
plt.show()
SymPyによる関数の式の表示
SymPyというライブラリを使えば、関数の式を表示することもできます。
import sympy as sy
まず、表示形式に関する設定を行います。
sy.init_printing(use_latex=False, use_unicode=True)
デフォルトでは式がlatexで表示されますが、
これだと出力が「1」などの数字単体の場合に見にくかったので
use_latex=False, use_unicode=True
にすることでUnicode文字として表示されるようにしました。
次に変数を設定します。
これを関数に代入することによって式を求めることが出来ます。
x1 = sy.Symbol("x1")
x2 = sy.Symbol("x2")
また、SymPyでは条件分岐の部分はそのままではエラーになってしまうので、
代わりにsy.Piecewise()
で条件を記述して関数を定義しなおします。
引数に(返す値, 条件)
という形のタプルを渡してやることで、条件分岐を行うことができます。
def AND(x1, x2):
x = np.array([x1, x2])
w = np.array([0.5, 0.5])
b = -0.7
tmp = np.sum(w * x) + b
return sy.Piecewise((0, tmp <= 0), (1, tmp > 0))
この関数に先程定義した変数を代入してやることで式を表示することができます。
AND(x1, x2)
(実行結果)
⎧0 for 0.5⋅x₁ + 0.5⋅x₂ - 0.7 ≤ 0
⎨
⎩1 otherwise
sy.Piecewise()
を使った状態でも、普通の関数と同様に計算したり結果を図示することが出来ます。
# ANDの領域を図示
plt.contourf(xx, yy, v_AND(xx, yy), cmap="Blues")
# 図の表示に関する設定
plt.grid() # グリッド線を表示
plt.colorbar() # カラーバーを表示
plt.xlim(xmin, xmax) # x軸の表示範囲を設定
plt.ylim(ymin, ymax) # y軸の表示範囲を設定
plt.xticks(np.arange(xmin, xmax + 0.01, tick_interval)) # x軸の目盛りを設定
plt.yticks(np.arange(ymin, ymax + 0.01, tick_interval)) # y軸の目盛りを設定
plt.xlabel("x1") # 横軸の名前を表示
plt.ylabel("x2") # 縦軸の名前を表示
plt.title("AND") # 図のタイトルを表示
plt.show()
参考ページ
matplotlibでの描写 等高線プロットの基礎をわかりやすく説明してみた - Qiita
numpy.vectorizeの使い方 - Qiita
matplotlib ログスケール表示とグリッド表示 - Qiita
SymPyで代数演算してみる - Qiita
SymPyで条件分岐をやってみる - Qiita
Printing — SymPy 1.8 documentation