Какова цель meshgrid в Python/NumPy?

Может кто - нибудь объяснить мне, что цель meshgrid функции в Numpy? Я знаю, что он создает какую-то сетку координат для построения графика, но я не могу видеть прямое ее преимущество.

Я изучаю "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)

Пожалуйста, по возможности, также покажите мне много примеров в реальном мире.

Ответ 1

Цель meshgrid - создать прямоугольную сетку из массива значений x и массив значений y.

Так, например, если мы хотим создать сетку, где у нас есть точка для каждого целого значения от 0 до 4 в обоих направлениях x и y. Чтобы создать прямоугольную сетку, нам нужна каждая комбинация точек x и y.

Это будет 25 очков, не так ли? Поэтому, если мы хотим создать массив x и y для всех этих точек, мы могли бы сделать следующее.

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

Очевидно, что это очень утомительно, особенно для больших диапазонов x и y. Вместо этого 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

Создание этих прямоугольных сеток полезно для ряда задач. В примере, который вы предоставили в своем сообщении, это просто способ выборки функции (sin(x**2 + y**2)/(x**2 + y**2)) в диапазоне значения для x и y.

Поскольку эта функция была выбрана на прямоугольной сетке, функция теперь может быть визуализирована как "изображение".

enter image description here

Кроме того, теперь результат может быть передан функциям, которые ожидают данные по прямоугольной сетке (то есть contourf)

Ответ 2

Предоставлено Microsoft Excel:

enter image description here

Ответ 3

Предположим, что у вас есть функция:

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()

введите описание изображения здесь

So np.meshgrid - просто удобство. В принципе то же самое можно сделать:

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

но вам нужно знать свои размеры (предположим, что у вас больше двух...) и правильное вещание. np.meshgrid делает все это для вас.

Также meshgrid позволяет удалять координаты вместе с данными, если вы, например, хотите сделать интерполяцию, но исключаете определенные значения:

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

Итак, как бы вы сделали интерполяцию сейчас? Вы можете дать x и y функцию интерполяции, такую ​​как scipy.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, может быть намного больше.

Ответ 4

На самом деле цель np.meshgrid уже упоминается в документации:

np.meshgrid

Вернуть координатные матрицы из координатных векторов.

Make N-D coordinate arrays for vectorized evaluations of N-D scalar/vector fields over N-D grids, given one-dimensional coordinate arrays x1, x2,..., xn.

Поэтому его основная цель состоит в создании координатных матриц.

Вы, наверное, просто спросили себя:

Зачем нам нужно создавать координатные матрицы?

Причина, по которой вам нужны координатные матрицы с Python/NumPy, заключается в том, что нет прямой связи между координатами и значениями, кроме случаев, когда ваши координаты начинаются с нуля и являются чисто положительными целыми числами. Тогда вы можете просто использовать индексы массива в качестве индекса. Однако, когда это не так, вам нужно как-то хранить координаты вместе с вашими данными. Вот где приходят сетки.

Предположим, ваши данные:

1  2  1
2  5  2
1  2  1

Однако каждое значение представляет собой область шириной 2 километра по горизонтали и 3 километра по вертикали. Предположим, ваше происхождение находится в верхнем левом углу, и вы хотите, чтобы массивы представляли расстояние, которое вы могли бы использовать:

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

Итак, если у вас есть два индекса, скажем, x и y (поэтому возвращаемое значение meshgrid обычно xx или xs вместо x, в этом случае я выбрал h ] по горизонтали!) тогда вы можете получить координату x точки, координату y точки и значение в этой точке, используя:

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

Это упрощает отслеживание координат. и (что еще более важно) вы можете передавать их функциям, которым необходимо знать координаты.

Немного более длинное объяснение

Однако сам по себе np.meshgrid часто не используется напрямую, в основном один просто использует один из похожих объектов np.mgrid или np.ogrid. Здесь np.mgrid представляет sparse=False и np.ogrid случай sparse=True (я ссылаюсь на аргумент sparse в np.meshgrid). Обратите внимание, что существует значительная разница между np.meshgrid и np.ogrid и np.mgrid: первые два возвращаемых значения (если их два или более) меняются местами. Часто это не имеет значения, но вы должны давать значимые имена переменных в зависимости от контекста.

Например, в случае двумерной сетки и matplotlib.pyplot.imshow имеет смысл назвать первый возвращенный элемент np.meshgrid x и второй y, пока он наоборот для np.mgrid и np.ogrid.

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]])

Это уже выглядит как координаты, в частности, линии x и y для 2D-графиков.

Визуализация:

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, эти массивы содержат все координаты xx и yy в -5 & lt; = xx & lt; = 5; -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 omitted here.

Даже если они также работают для 1D, есть две (гораздо более распространенные) функции создания сетки 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.]])

Приложения

Вы специально задали вопрос о цели, и на самом деле эти сетки чрезвычайно полезны, если вам нужна система координат.

Например, если у вас есть функция 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

Однако, поскольку imshow не поддерживает входы x и 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.

Или приведу другой забавный пример с использованием моделей астропии (на этот раз меня не волнуют координаты, я просто использую их для создания сетки):

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.interp2d, scipy.interpolate.griddata даже показывают примеры использования np.mgrid) в Scipy и т.д. требуют сеток. Большинство из них работают с открытыми сетками и плотными сетками, однако некоторые работают только с одним из них.

Ответ 5

meshgrid помогает создать прямоугольную сетку из двух одномерных массивов всех пар точек из двух массивов.

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))

Скажем, если ваша функция просто производит продукт из двух элементов, то именно так можно добиться декартова продукта, эффективно для больших массивов.

Отправлено отсюда