Я изучаю "Python Machine Learning" у Себастьяна Рашка, и он использует его для построения границ решения. См. Вход 11 здесь.
Я также пробовал этот код из официальной документации, но, опять же, выход не имеет для меня никакого смысла.
Пожалуйста, по возможности, также покажите мне много примеров в реальном мире.
Ответ 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 и т.д. требуют сеток. Большинство из них работают с открытыми сетками и плотными сетками, однако некоторые работают только с одним из них.