web-dev-qa-db-ja.com

Python/NumPyにおけるmeshgridの目的は何ですか?

誰かが私にNumpyのmeshgrid関数の目的は何かを説明できますか?私はそれがプロットのためにある種の座標グリッドを作成することを知っています、しかし私は実際にそれの直接的な利益を見ることができません。

私はSebastian Raschkaの "Python Machine Learning"を研究しています、そして彼はそれを意思決定の境界線を描くために使っています。入力11 ここ を参照してください。

私も公式のドキュメントからこのコードを試してみましたが、やはり、出力は私には意味がありません。

x = np.arange(-5, 5, 1)
y = np.arange(-5, 5, 1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)

可能であれば、実世界での例もたくさん見せてください。

199
HonzaB

meshgridの目的は、x値の配列とy値の配列から長方形のグリッドを作成することです。

したがって、たとえば、x方向とy方向の両方向で0から4までの各整数値に点があるグリッドを作成するとします。長方形のグリッドを作成するには、xyのあらゆる組み合わせが必要です。

これは25ポイントになるでしょうね。そのため、これらすべての点に対してxとyの配列を作成したい場合は、次のようにcouldを実行します。

x[0,0] = 0    y[0,0] = 0
x[0,1] = 1    y[0,1] = 0
x[0,2] = 2    y[0,2] = 0
x[0,3] = 3    y[0,3] = 0
x[0,4] = 4    y[0,4] = 0
x[1,0] = 0    y[1,0] = 1
x[1,1] = 1    y[1,1] = 1
...
x[4,3] = 3    y[4,3] = 4
x[4,4] = 4    y[4,4] = 4

これにより、次のxおよびy行列が生成され、各行列内の対応する要素のペアがグリッド内の点のx座標とy座標を示します。

x =   0 1 2 3 4        y =   0 0 0 0 0
      0 1 2 3 4              1 1 1 1 1
      0 1 2 3 4              2 2 2 2 2
      0 1 2 3 4              3 3 3 3 3
      0 1 2 3 4              4 4 4 4 4

次にこれらをプロットして、それらがグリッドであることを確認します。

plt.plot(x,y, marker='.', color='k', linestyle='none')

enter image description here

明らかに、これは特に広範囲のxyに対して非常に面倒です。代わりに、meshgridが実際にこれを生成します。指定する必要があるのは、一意のxおよびy値だけです。

xvalues = np.array([0, 1, 2, 3, 4]);
yvalues = np.array([0, 1, 2, 3, 4]);

さて、meshgridを呼び出すと、前の出力が自動的に得られます。

xx, yy = np.meshgrid(xvalues, yvalues)

plt.plot(xx, yy, marker='.', color='k', linestyle='none')

enter image description here

これらの長方形グリッドの作成は、いくつかの作業に役立ちます。あなたの投稿で提供した例では、それは単にxyの値の範囲にわたって関数(sin(x**2 + y**2) / (x**2 + y**2))をサンプリングする方法です。

この関数は長方形のグリッド上でサンプリングされているので、この関数は「画像」として視覚化することができます。

enter image description here

さらに、結果は矩形グリッド上のデータを期待する関数に渡すことができます(すなわちcontourf

269
Suever

Microsoft Excelleのご好意により:

enter image description here

152
Hai Phan

関数があるとします。

def sinus2d(x, y):
    return np.sin(x) + np.sin(y)

たとえば、0から2 * piの範囲でどのように見えるかを確認したいとします。どうしますか? np.meshgridが入ってきます:

xx, yy = np.meshgrid(np.linspace(0,2*np.pi,100), np.linspace(0,2*np.pi,100))
z = sinus2d(xx, yy) # Create the image on this grid

そのようなプロットは次のようになります。

import matplotlib.pyplot as plt
plt.imshow(z, Origin='lower', interpolation='none')
plt.show()

enter image description here

だからnp.meshgridは単なる便利です。原則として、同じことが以下の方法でも可能です。

z2 = sinus2d(np.linspace(0,2*np.pi,100)[:,None], np.linspace(0,2*np.pi,100)[None,:])

しかし、あなたはあなたの次元(あなたが2つ以上持っていると仮定します...)と正しい放送を知っている必要があります。 np.meshgridはあなたに代わってこれらすべてを行います。

例えば、補間をしたいが特定の値を除外したい場合、meshgridを使用すると、データと一緒に座標を削除できます。

condition = z>0.6
z_new = z[condition] # This will make your array 1D

それでは、補間はどのようにして行うのでしょうか。 xyscipy.interpolate.interp2dのような補間関数に与えることができるので、どの座標が削除されたかを知る方法が必要です。

x_new = xx[condition]
y_new = yy[condition]

それから、「正しい」座標で補間することができます(meshgridを使わずに試してみると、追加のコードがたくさんあります)。

from scipy.interpolate import interp2d
interpolated = interp2(x_new, y_new, z_new)

そして元のmeshgridを使えば、元のグリッド上で内挿を再び得ることができます。

interpolated_grid = interpolated(xx, yy)

これらは私がmeshgridを使った例にすぎません。

31
MSeifert

実際、np.meshgridの目的はすでにドキュメントで言及されています:

np.meshgrid

座標ベクトルから座標行列を返します。

1次元座標配列x1、x2、...、xnを指定して、N-Dグリッド上のN-Dスカラー/ベクトルフィールドのベクトル化評価用のN-D座標配列を作成します。

そのため、主な目的は座標行列を作成することです。

あなたはおそらく自分自身に尋ねました:

なぜ座標行列を作成する必要があるのですか?

Python/NumPyで座標行列が必要な理由は、座標がゼロで始まり、純粋に正の整数である場合を除き、座標から値への直接の関係がないためです。次に、配列のインデックスをインデックスとして使用できます。ただし、そうでない場合は、何らかの方法でデータと一緒に座標を保存する必要があります。そこでグリッドが登場します。

データが次のとおりであるとします:

1  2  1
2  5  2
1  2  1

ただし、各値は、水平方向に2キロメートル、垂直方向に3キロメートルの領域を表します。 Originが左上隅にあり、使用できる距離を表す配列が必要だとします。

import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)

vは次のとおりです。

0  2  4
0  2  4
0  2  4

およびh:

0  0  0
3  3  3
6  6  6

したがって、2つのインデックスがある場合、xyを使用します(そのため、meshgridの戻り値は通常、xxではなくxsまたはxです。 ] _この場合、水平方向にhを選択しました!)を使用して、ポイントのx座標、ポイントのy座標、およびそのポイントの値を取得できます。

h[x, y]    # horizontal coordinate
v[x, y]    # vertical coordinate
data[x, y]  # value

これにより、座標および(さらに重要なこと)を追跡しやすくなり、座標を知る必要がある関数に渡すことができます。

少し長い説明

ただし、np.meshgrid自体は直接使用されることはあまりなく、ほとんどの場合、similarオブジェクトnp.mgridまたはnp.ogridのいずれかを使用します。ここで、np.mgridsparse=Falseを表し、np.ogridsparse=Trueの場合を表します(np.meshgridsparse引数を参照します)。 np.meshgridnp.ogridnp.mgridには大きな違いがあることに注意してください。最初の2つの戻り値(2つ以上ある場合)は逆になります。多くの場合、これは重要ではありませんが、コンテキストに応じて意味のある変数名を指定する必要があります。

たとえば、2Dグリッドおよびmatplotlib.pyplot.imshowの場合、np.meshgridxの最初に返された項目に名前を付け、np.mgridおよびnp.ogridの場合は2番目の項目にyという名前を付けるのが理にかなっています。

np.ogrid およびスパースグリッド

>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5],
       [-4],
       [-3],
       [-2],
       [-1],
       [ 0],
       [ 1],
       [ 2],
       [ 3],
       [ 4],
       [ 5]])

すでに述べたように、出力はnp.meshgridと比較すると逆になります。そのため、yy, xxではなくxx, yyとしてアンパックしました。

>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5],
       [-4],
       [-3],
       [-2],
       [-1],
       [ 0],
       [ 1],
       [ 2],
       [ 3],
       [ 4],
       [ 5]])

これはすでに座標、特に2Dプロットのxおよびy線のように見えます。

視覚化:

yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")

enter image description here

np.mgrid および密集/肉付けされたグリッド

>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
       [-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
       [-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
       [-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
       [ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2],
       [ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3],
       [ 4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4],
       [ 5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5]])

ここでも同じことが言えます。出力はnp.meshgridと比べて逆になります。

>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4,  5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
       [-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
       [-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
       [-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1],
       [ 2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2],
       [ 3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3],
       [ 4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4],
       [ 5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5]])

ogridとは異なり、これらの配列には-5 <= xx <= 5のallxxおよびyy座標が含まれます。 ; -5 <= yy <= 5グリッド。

yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")

enter image description here

機能性

2Dに限定されるだけでなく、これらの関数は任意の次元で動作します(まあ、Pythonで関数に与えられる引数の最大数とNumPyが許可する最大数の次元があります):

>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
...     print('x{}'.format(i+1))
...     print(repr(x))
x1
array([[[[0]]],


       [[[1]]],


       [[[2]]]])
x2
array([[[[1]],

        [[2]],

        [[3]]]])
x3
array([[[[2],
         [3],
         [4]]]])
x4
array([[[[3, 4, 5]]]])

>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
...     print('x{}'.format(i+1))
...     print(repr(x))
# Identical output so it's omitted here.

これらが1Dでも機能する場合でも、2つの(より一般的な)1Dグリッド作成関数があります。

startおよびstop引数に加えて、step引数もサポートします(ステップ数を表す複雑なステップでも)。

>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1  # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
       [3., 3., 3., 3.],
       [5., 5., 5., 5.],
       [7., 7., 7., 7.],
       [9., 9., 9., 9.]])
>>> x2  # The dimension with the "number of steps"
array([[ 1.,  4.,  7., 10.],
       [ 1.,  4.,  7., 10.],
       [ 1.,  4.,  7., 10.],
       [ 1.,  4.,  7., 10.],
       [ 1.,  4.,  7., 10.]])

用途

目的について具体的に尋ねましたが、実際、これらのグリッドは座標系が必要な場合に非常に役立ちます。

たとえば、2次元で距離を計算するNumPy関数がある場合:

def distance_2d(x_point, y_point, x, y):
    return np.hypot(x-x_point, y-y_point)

そして、各ポイントの距離を知りたい:

>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys)  # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
        7.07106781, 7.        , 7.07106781, 7.28010989, 7.61577311],
       [8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
        6.08276253, 6.        , 6.08276253, 6.32455532, 6.70820393],
       [7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
        5.09901951, 5.        , 5.09901951, 5.38516481, 5.83095189],
       [7.21110255, 6.40312424, 5.65685425, 5.        , 4.47213595,
        4.12310563, 4.        , 4.12310563, 4.47213595, 5.        ],
       [6.70820393, 5.83095189, 5.        , 4.24264069, 3.60555128,
        3.16227766, 3.        , 3.16227766, 3.60555128, 4.24264069],
       [6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
        2.23606798, 2.        , 2.23606798, 2.82842712, 3.60555128],
       [6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
        1.41421356, 1.        , 1.41421356, 2.23606798, 3.16227766],
       [6.        , 5.        , 4.        , 3.        , 2.        ,
        1.        , 0.        , 1.        , 2.        , 3.        ],
       [6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
        1.41421356, 1.        , 1.41421356, 2.23606798, 3.16227766],
       [6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
        2.23606798, 2.        , 2.23606798, 2.82842712, 3.60555128]])

出力は、オープングリッドではなく高密度グリッドで渡された場合、同一になります。 NumPys放送はそれを可能にします!

結果を視覚化しましょう:

plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, Origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel())  # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()

enter image description here

また、NumPys mgridおよびogridが非常に便利になるのは、グリッドの解像度を簡単に変更できるためです。

ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

enter image description here

ただし、imshowxおよびy入力をサポートしていないため、目盛りを手動で変更する必要があります。 x座標とy座標を受け入れると本当に便利ですよね?

グリッドを自然に処理する関数をNumPyで簡単に作成できます。さらに、NumPy、SciPy、matplotlibには、グリッドを渡すことを期待する関数がいくつかあります。

私は画像が好きなので、調べましょう matplotlib.pyplot.contour

ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)

enter image description here

座標がすでに正しく設定されていることに注意してください! densityを渡しただけの場合はそうではありません。

または、 astropy models を使用して別の楽しい例を示します(今回は座標をあまり気にせず、それらを使用してsomeグリッドを作成します) :

from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
    g2d = models.Gaussian2D(amplitude=100, 
                           x_mean=np.random.randint(0, 100), 
                           y_mean=np.random.randint(0, 100), 
                           x_stddev=3, 
                           y_stddev=3)
    z += g2d(x, y)
    a2d = models.AiryDisk2D(amplitude=70, 
                            x_0=np.random.randint(0, 100), 
                            y_0=np.random.randint(0, 100), 
                            radius=5)
    z += a2d(x, y)

enter image description here

それは機能モデルとフィッティングに関連するいくつかの関数(たとえば scipy.interpolate.interp2dscipy.interpolate.griddata でさえ、見た目のため)ですが、Scipyなどでは、グリッドを必要とするnp.mgridを使用した例を示しています。これらのほとんどは、オープングリッドと密グリッドで機能しますが、一部はそれらの1つでのみ機能します。

30
MSeifert

meshgridは、2つの配列からのすべての点のペアからなる2つの1-D配列から長方形のグリッドを作成するのに役立ちます。

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

さて、もし関数f(x、y)を定義していて、配列 'x'と 'y'からの可能なすべての点の組み合わせにこの関数を適用したいのであれば、こうすることができます。

f(*np.meshgrid(x, y))

たとえば、関数が2つの要素の積を生成するだけであれば、大規模配列に対して効率的にデカルト積を実現できます。

ここ から参照

1
Narasimhan