静かなる名辞

pythonとプログラミングのこと

2019/03/22:TechAcademyがteratailの質問・回答を盗用していた件
2019/03/26:TechAcademy盗用事件 公式発表と深まる疑念


【python】numpy.meshgridの基本的な使い方まとめ

はじめに

 numpyのmeshgridの使い方があまり理解できなくて、なんとなくコピペで動かしていたので、どのようなものなのかまとめておくことにしました。

 目次

とりあえずmeshgridを作ってみる

 meshgrid自体はこのように何の変哲もないものです。

>>> import numpy as np
>>> a = np.arange(0,3,0.5)
>>> b = np.arange(0,10,2)
>>> a
array([0. , 0.5, 1. , 1.5, 2. , 2.5])
>>> b
array([0, 2, 4, 6, 8])
>>> X, Y = np.meshgrid(a, b)
>>> X
array([[0. , 0.5, 1. , 1.5, 2. , 2.5],
       [0. , 0.5, 1. , 1.5, 2. , 2.5],
       [0. , 0.5, 1. , 1.5, 2. , 2.5],
       [0. , 0.5, 1. , 1.5, 2. , 2.5],
       [0. , 0.5, 1. , 1.5, 2. , 2.5]])
>>> Y
array([[0, 0, 0, 0, 0, 0],
       [2, 2, 2, 2, 2, 2],
       [4, 4, 4, 4, 4, 4],
       [6, 6, 6, 6, 6, 6],
       [8, 8, 8, 8, 8, 8]])

 つまり(0,0)の値を(X[0,0],Y[0,0])として表現できる。ここまでは常識的な話。

計算する

 numpy配列なので、配列全体でそのまま計算することができます。numpyでいうところの[1, 2, 3] + [4, 5, 6]が[5, 7, 9]になるのと同じです(この表記はリストのリテラルなのでできませんが)。

>>> Z = np.sin(X+Y)
>>> Z
array([[ 0.        ,  0.47942554,  0.84147098,  0.99749499,  0.90929743,
         0.59847214],
       [ 0.90929743,  0.59847214,  0.14112001, -0.35078323, -0.7568025 ,
        -0.97753012],
       [-0.7568025 , -0.97753012, -0.95892427, -0.70554033, -0.2794155 ,
         0.21511999],
       [-0.2794155 ,  0.21511999,  0.6569866 ,  0.93799998,  0.98935825,
         0.79848711],
       [ 0.98935825,  0.79848711,  0.41211849, -0.07515112, -0.54402111,
        -0.87969576]])

 ま、これはmeshgridの機能というより、numpyの機能。

plotしてみる

 ぶっちゃけ3Dのplot以外でmeshgrid使うことってあるんですか・・・?

>>> import matplotlib.pyplot as plt
>>> from mpl_toolkits.mplot3d import Axes3D
>>> fig = plt.figure()
>>> ax = Axes3D(fig)
>>> ax.plot_wireframe(X, Y, Z)
<mpl_toolkits.mplot3d.art3d.Line3DCollection object at 0x7f04d0367860>
>>> plt.show()

meshgridを使って三次元プロット
meshgridを使って三次元プロット

 XとYを足してsinに通すという謎の関数にしてしまったので見た目は気持ち悪いですが、それはさておきうまくプロットすることができています。matplotlibには同じような3次元データのプロット用の関数がたくさんあり、だいたいmeshgridを受け付けるので、いろいろな方法でプロットすることができます。

xyz座標の配列に変換する

 meshgridからx,y,zの座標列に変換したい、ということもあるでしょう。あまり難しく考える必要はなくて、Xをflattenすればx座標列が、Yをflattenすれば……というように座標を得ることができ、あとは適当に結合すれば任意の形にできます。

>>> x = X.ravel()
>>> y = Y.ravel()
>>> z = Z.ravel()
>>> x.shape
(30,)
>>> y.shape
(30,)
>>> z.shape
(30,)
>>> x
array([0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 0. ,
       0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5, 1. , 1.5, 2. , 2.5, 0. , 0.5,
       1. , 1.5, 2. , 2.5])
>>> y
array([0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6,
       6, 6, 8, 8, 8, 8, 8, 8])
>>> z
array([ 0.        ,  0.47942554,  0.84147098,  0.99749499,  0.90929743,
        0.59847214,  0.90929743,  0.59847214,  0.14112001, -0.35078323,
       -0.7568025 , -0.97753012, -0.7568025 , -0.97753012, -0.95892427,
       -0.70554033, -0.2794155 ,  0.21511999, -0.2794155 ,  0.21511999,
        0.6569866 ,  0.93799998,  0.98935825,  0.79848711,  0.98935825,
        0.79848711,  0.41211849, -0.07515112, -0.54402111, -0.87969576])

 こうすると色々な関数に渡せそうで便利。結合については、こちらの記事を参照してください。

www.haya-programming.com

 たとえばxyzで(n_samples, 3)にしたければnp.stack([x, y, z], axis=1)などでよさそうです。

逆にxyz座標からmeshgridを生成する

 x, y, zの座標データが与えられていて、プロットするためにmeshgridに変換したいというシチュエーションもあります。

 この場合は元のデータが都合よくグリッド状になっていないことが多いので、補完という処理をした上で変換することが可能です。

 詳細はこちらの記事を御覧ください。

www.haya-programming.com

まとめ

 いろいろ動かしてみると、それなりにやっていることが単純なのがわかって、親近感が湧いてきました。とにかく三次元プロットでは必需品なので、meshgridは使いこなそうということです。