Qual é o objetivo do meshgrid no Python / NumPy?

303

Alguém pode me explicar qual é o objetivo da meshgridfunção no Numpy? Eu sei que isso cria algum tipo de grade de coordenadas para plotagem, mas não consigo ver o benefício direto disso.

Estou estudando "Python Machine Learning" de Sebastian Raschka, e ele está usando-o para traçar as fronteiras da decisão. Veja a entrada 11 aqui .

Eu também tentei esse código na documentação oficial, mas, novamente, a saída realmente não faz sentido para mim.

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)

Por favor, se possível, também me mostre muitos exemplos do mundo real.

HonzaB
fonte

Respostas:

391

O objetivo de meshgridé criar uma grade retangular a partir de uma matriz de valores x e uma matriz de valores y.

Assim, por exemplo, se queremos criar uma grade em que temos um ponto em cada valor inteiro entre 0 e 4 nas direções x e y. Para criar uma grade retangular, precisamos de todas as combinações dos pontos xe y.

Serão 25 pontos, certo? Portanto, se desejássemos criar uma matriz xey para todos esses pontos, poderíamos fazer o seguinte.

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

Isso resultaria no seguinte xe em ymatrizes, de modo que o emparelhamento do elemento correspondente em cada matriz forneça as coordenadas x e y de um ponto na grade.

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

Podemos então plotá-los para verificar se eles são uma grade:

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

insira a descrição da imagem aqui

Obviamente, isso fica muito tedioso, especialmente para grandes faixas de xe y. Em vez disso, meshgridpode realmente gerar isso para nós: tudo o que precisamos especificar são os únicos xe os yvalores.

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

Agora, quando ligamos meshgrid, obtemos a saída anterior automaticamente.

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

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

insira a descrição da imagem aqui

A criação dessas grades retangulares é útil para várias tarefas. No exemplo que você forneceu em sua postagem, é simplesmente uma maneira de provar uma função ( sin(x**2 + y**2) / (x**2 + y**2)) em um intervalo de valores para xe y.

Como essa função foi amostrada em uma grade retangular, a função agora pode ser visualizada como uma "imagem".

insira a descrição da imagem aqui

Além disso, o resultado agora pode ser passado para funções que esperam dados na grade retangular (ou seja contourf)

Suever
fonte
10
Você não explicou os valores de retorno xxe yy. A parte misteriosa para mim foi por que ele retorna esse par de resultados e como eles são. A resposta de Hai Phan é útil para isso. Eu acho que faz isso por conveniência, já que o enredo quer dois parâmetros assim.
Nealmcb 25/04
2
Eu não sei - é por isso que estou procurando essas informações;) Portanto, não estou dizendo que deva retornar algo diferente. Estou apenas dando o meu melhor palpite sobre uma informação que está faltando para aqueles que acabaram de ler a resposta aceita. E se você quiser, estou sugerindo que sua resposta (que já é muito boa - obrigada!) Seria um pouco mais completa se você explicasse os valores de retorno (como Hai fez), para aqueles que ainda estão intrigados.
Nealmcb
1
Para entender melhor os valores dos xx e yy, considere a alegação de que o código a seguir você recebe o mesmo resultado que np.meshgrid:xx = [xvalues for y in yvalues] yy = [[y for x in xvalues] for y in yvalues]
Matt Kleinsmith
1
Esta resposta é confusa: não é sua primeira ilustração xe ypara trás? Quando você o faz xx, yy = np.meshgrid(np.arange(4), np.arange(4)), é o inverso do que você tem xe yna primeira parte da resposta. mgridCorresponde à ordem das saídas para , mas não para o meshgrid. Ele xxdeve estar aumentando na direção x, mas o seu aumenta na direção y.
Scott Staniewicz 28/07
1
@ScottStaniewicz Obrigado por apontar que nossa, agora tenho certeza de como eu estraguei tudo isso ... Atualizado!
Suever 29/07
249

Cortesia do Microsoft Excel: 

insira a descrição da imagem aqui

Salsaparrilha
fonte
6
Agradável. Fwiw, se você deseja uma matriz 2 x 12 dos pares no meio:XYpairs = np.vstack([ XX.reshape(-1), YY.reshape(-1) ])
denis 14/03
5
e se você quiser uma matriz 12 x 2 dos pares no meio:XYpairs = np.dstack([XX, YY]).reshape(-1, 2)
barlaensdoonn
2
Boa resposta. O objetivo do meshgrid é criar uma grade usando a coordenada de cada dim.
Bom menino
1
O que eu acho um pouco estranho é que os valores xey são retornados separadamente, em vez de já combinados em uma matriz. Se eu quiser eles em uma matriz, eu preciso fazer:np.vstack([XX.ravel(), YY.ravel()]).T
user3629892
65

Na verdade, o objetivo de np.meshgridjá está mencionado na documentação:

np.meshgrid

Retorne matrizes de coordenadas a partir de vetores de coordenadas.

Faça matrizes de coordenadas ND para avaliações vetorizadas de campos escalares / vetor ND sobre grades ND, considerando matrizes de coordenadas unidimensionais x1, x2, ..., xn.

Portanto, seu principal objetivo é criar matrizes de coordenadas.

Você provavelmente só se perguntou:

Por que precisamos criar matrizes de coordenadas?

O motivo pelo qual você precisa de matrizes de coordenadas com Python / NumPy é que não há relação direta entre coordenadas e valores, exceto quando suas coordenadas começam com zero e são inteiros puramente positivos. Então você pode apenas usar os índices de uma matriz como o índice. No entanto, quando esse não for o caso, você precisará armazenar coordenadas de alguma forma com seus dados. É aí que as redes entram.

Suponha que seus dados sejam:

1  2  1
2  5  2
1  2  1

No entanto, cada valor representa uma região de 2 km de largura horizontalmente e 3 km de vertical. Suponha que sua origem seja o canto superior esquerdo e você deseje matrizes que representem a distância que você poderia usar:

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

onde v é:

array([[0, 0, 0],
       [2, 2, 2],
       [4, 4, 4]])

e h:

array([[0, 3, 6],
       [0, 3, 6],
       [0, 3, 6]])

Portanto, se você tiver dois índices, digamos xe y(é por isso que o valor de retorno meshgridé geralmente xxou em xsvez de x, neste caso, eu escolhi hhorizontalmente!), Então você pode obter a coordenada x do ponto, a coordenada y do ponto e a valor nesse ponto usando:

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

Isso facilita muito o controle das coordenadas e (ainda mais importante) você pode transmiti-las para funções que precisam conhecer as coordenadas.

Uma explicação um pouco mais longa

No entanto, np.meshgridele próprio não costuma ser usado diretamente, principalmente se usa apenas objetos semelhantesnp.mgrid ou np.ogrid. Aqui np.mgridrepresenta o sparse=Falsee np.ogrido sparse=Truecaso (refiro-me ao sparseargumento de np.meshgrid). Observe que há uma diferença significativa entre np.meshgride np.ogride np.mgrid: Os dois primeiros valores retornados (se houver dois ou mais) são revertidos. Geralmente isso não importa, mas você deve fornecer nomes significativos de variáveis, dependendo do contexto.

Por exemplo, no caso de uma grade 2D e matplotlib.pyplot.imshowfaz sentido nomear o primeiro item retornado np.meshgrid xe o segundo yenquanto é o contrário de np.mgride np.ogrid.

np.ogrid e grades esparsas

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

Como já foi dito, a saída é revertida quando comparada a np.meshgrid, é por isso que eu a descompactei como em yy, xxvez de 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]])

Isso já parece coordenadas, especificamente as linhas x e y para plotagens 2D.

Visualizado:

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

insira a descrição da imagem aqui

np.mgrid e grades densas / polidas

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

O mesmo se aplica aqui: A saída é revertida em comparação com 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]])

Diferentemente ogriddessas matrizes, contém todas as coordenadas xxe yy-5 <= xx <= 5; -5 <= aa <= 5 grade.

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

insira a descrição da imagem aqui

Funcionalidade

Não se limita apenas ao 2D, essas funções funcionam para dimensões arbitrárias (bem, há um número máximo de argumentos dados para funcionar no Python e um número máximo de dimensões que o NumPy permite):

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

Mesmo que isso também funcione para 1D, existem duas (muito mais comuns) funções de criação de grade 1D:

Além do argumento starte, stopele também suporta o stepargumento (mesmo etapas complexas que representam o número de etapas):

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

Formulários

Você perguntou especificamente sobre o objetivo e, de fato, essas grades são extremamente úteis se você precisar de um sistema de coordenadas.

Por exemplo, se você tiver uma função NumPy que calcula a distância em duas dimensões:

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

E você quer saber a distância de cada ponto:

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

A saída seria idêntica se alguém passasse em uma grade densa em vez de uma grade aberta. A transmissão do NumPys torna isso possível!

Vamos visualizar o resultado:

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

insira a descrição da imagem aqui

E este é também quando NumPys mgride ogridtornar-se muito conveniente, pois permite que você altere facilmente a resolução de suas grades:

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

insira a descrição da imagem aqui

No entanto, como imshownão suporta xe yinsere, é necessário alterar os ticks manualmente. Seria realmente conveniente se ele aceitasse as coordenadas xe y, certo?

É fácil escrever funções com o NumPy que lidam naturalmente com grades. Além disso, existem várias funções no NumPy, SciPy, matplotlib que esperam que você passe na grade.

Eu gosto de imagens, então vamos explorar 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)

insira a descrição da imagem aqui

Observe como as coordenadas já estão definidas corretamente! Esse não seria o caso se você apenas passasse no density.

Ou, para dar outro exemplo divertido usando modelos de astropia (desta vez não me importo muito com as coordenadas, apenas as uso para criar uma grade):

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)

insira a descrição da imagem aqui

Embora isso seja apenas "para a aparência", várias funções relacionadas a modelos funcionais e acessórios (por exemplo scipy.interpolate.interp2d, scipy.interpolate.griddataaté mostram exemplos usando np.mgrid) no Scipy etc. requerem grades. A maioria deles trabalha com grades abertas e grades densas, no entanto, algumas funcionam apenas com uma delas.

MSeifert
fonte
Eu só quero agradecer muito por esta resposta extremamente detalhada. Isto fez o meu dia.
Jlanger 6/04
Que maneira bonita de responder uma pergunta ... tão detalhada. Obrigado
Bipin
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)- uma vez que são 2 km na horizontal e 3 km na vertical, o primeiro intervalo não deve ser multiplicado por 2 e o segundo por 3?
Nixt 8/06
@ Nixt Infelizmente, não é tão simples assim. Talvez eu precise verificar essa parte da resposta novamente. É uma troca entre a exibição transposta da matriz e a indexação invertida - normalmente você espera que o primeiro índice seja horizontal e o segundo vertical, mas a exibição será transposta. No entanto, esse é principalmente um detalhe que, esperamos, não invalida a essência da resposta, que visa ilustrar o motivo das grades. Mas vou tentar revisar isso em uma data futura.
MSeifert
36

Suponha que você tenha uma função:

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

e você deseja, por exemplo, ver como fica no intervalo de 0 a 2 * pi. Como você faria? Aí np.meshgridentra:

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

e esse enredo seria semelhante a:

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

insira a descrição da imagem aqui

Então, np.meshgridé apenas uma conveniência. Em princípio, o mesmo poderia ser feito por:

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

mas é preciso estar ciente de suas dimensões (suponha que você tenha mais de duas ...) e a transmissão correta. np.meshgridfaz tudo isso para você.

Além disso, o meshgrid permite excluir coordenadas juntamente com os dados se, por exemplo, você desejar fazer uma interpolação, mas excluir determinados valores:

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

então, como você faria a interpolação agora? Você pode dar xe ypara uma função de interpolação como scipy.interpolate.interp2dentão você precisa encontrar uma maneira de saber quais as coordenadas foram excluídos:

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

e então você ainda pode interpolar com as coordenadas "corretas" (tente sem o meshgrid e você terá muito código extra):

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

e a malha original permite obter a interpolação na grade original novamente:

interpolated_grid = interpolated(xx[0], yy[:, 0]).reshape(xx.shape)

Estes são apenas alguns exemplos em que eu usei o meshgridpode haver muito mais.

MSeifert
fonte
1
Obrigado pela sua resposta! O momento mais confuso para mim é devolvido valores xx, yy. Era difícil entender o que são e por que os usamos para calcular a função. Parece que eu entendi. Queremos calcular alguma função com base em coordenadas. Podemos escrever algo assim: em for x=1:10: for y=1:10: z[x,y]=sin(x)+sin(y)vez disso, calculamos zde uma maneira diferente z=sin([x,x,...,x]) + sin([y,y,..y]). Corrija-me se eu estiver errada!
Alena Kastsiukavets
Não é 100% código pseudo correto, mas eu espero que você ver o meu ponto)
Alena Kastsiukavets
Na verdade, você sempre precisa do loop duplo (seu primeiro código). Mas existem diferentes maneiras de numpyarquivá- lo com : malha ou transmissão. Se você não descarta pontos (veja a última parte da minha resposta), ambos são realmente funcionais equivalentes. A transmissão é apenas um loop implícito na dimensão a ser transmitida. Observe que eu usei [:,None]e [None, :]incluí dimensões extras para que o resultado seja transmitido corretamente. Seu segundo exemplo é mais como:sin([[y],[y],..[y]])
MSeifert
Uma ilustração muito legal. Obrigado por colocar tanto esforço.
natersoz
interpolated_grid = interpolated(xx, yy)- isso não funciona para mim, erro:x and y should both be 1-D arrays
Nixt
4

O meshgrid ajuda a criar uma grade retangular a partir de duas matrizes 1-D de todos os pares de pontos das duas matrizes.

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

Agora, se você definiu uma função f (x, y) e deseja aplicar essa função a toda a combinação possível de pontos das matrizes 'x' e 'y', pode fazer o seguinte:

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

Digamos, se sua função produz apenas o produto de dois elementos, é assim que um produto cartesiano pode ser alcançado, com eficiência, para grandes matrizes.

Referido a partir daqui

Narasimhan
fonte
1

Ideia básica

Dados os possíveis valores de x xs, (pense neles como as marcas no eixo x de um gráfico) e os possíveis valores de y ys, meshgridgera o conjunto correspondente de pontos de grade (x, y) --- análogos a set((x, y) for x in xs for y in yx). Por exemplo, se xs=[1,2,3]e ys=[4,5,6], obteríamos o conjunto de coordenadas {(1,4), (2,4), (3,4), (1,5), (2,5), (3,5), (1,6), (2,6), (3,6)}.

Forma do valor de retorno

No entanto, a representação que meshgridretorna é diferente da expressão acima de duas maneiras:

Primeiro , meshgridexpõe os pontos da grade em uma matriz 2D: linhas correspondem a diferentes valores y, colunas correspondem a diferentes valores x --- como em list(list((x, y) for x in xs) for y in ys), o que daria a seguinte matriz:

   [[(1,4), (2,4), (3,4)],
    [(1,5), (2,5), (3,5)],
    [(1,6), (2,6), (3,6)]]

Segundo , meshgridretorna as coordenadas x e y separadamente (ou seja, em duas matrizes 2d numpy diferentes):

   xcoords, ycoords = (
       array([[1, 2, 3],
              [1, 2, 3],
              [1, 2, 3]]),
       array([[4, 4, 4],
              [5, 5, 5],
              [6, 6, 6]]))
   # same thing using np.meshgrid:
   xcoords, ycoords = np.meshgrid([1,2,3], [4,5,6])
   # same thing without meshgrid:
   xcoords = np.array([xs] * len(ys)
   ycoords = np.array([ys] * len(xs)).T

Observe np.meshgridque também pode gerar grades para dimensões mais altas. Dados xs, ys e zs, você recuperaria xcoords, ycoords, zcoords como matrizes 3D. meshgridtambém suporta a ordem inversa das dimensões, bem como a representação esparsa do resultado.

Formulários

Por que queremos essa forma de saída?

Aplique uma função em todos os pontos da grade: Uma motivação é que operadores binários como (+, -, *, /, **) sejam sobrecarregados para matrizes numpy como operações elementares. Isso significa que, se eu tiver uma função def f(x, y): return (x - y) ** 2que funcione em dois escalares, também posso aplicá-la em duas matrizes numpy para obter uma matriz de resultados elementares: por exemplo, f(xcoords, ycoords)ou f(*np.meshgrid(xs, ys))forneça o seguinte no exemplo acima:

array([[ 9,  4,  1],
       [16,  9,  4],
       [25, 16,  9]])

Superior produto externo dimensional: Eu não tenho certeza o quão eficiente este é, mas você pode obter produtos exteriores elevadas dimensões desta forma: np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0).

Gráficos de contorno no matplotlib: deparei-me meshgridao investigar desenho de gráficos de contorno com matplotlib para plotar limites de decisão . Para isso, você gera uma grade com meshgrid, avalia a função em cada ponto da grade (por exemplo, como mostrado acima) e depois passa os xcoords, ycoords e os valores f calculados (ou seja, zcoords) para a função de contorno.

user3780389
fonte