Python numpy: crea una matriz 2d de valores basados ​​en coordenadas

Tengo un archivo que contiene 3 columnas, donde las dos primeras son coordenadas (x, y) y la tercera es un valor (z) correspondiente a esa posición. Aquí hay un breve ejemplo:

xyz 0 1 14 0 2 17 1 0 15 1 1 16 2 1 18 2 2 13 

Quiero crear una matriz 2D de valores de la tercera fila en función de sus coordenadas x, y en el archivo. Leí en cada columna como una matriz individual, y creé cuadrículas de valores x y valores y usando numpy.meshgrid, como esto:

 x = [[0 1 2] and y = [[0 0 0] [0 1 2] [1 1 1] [0 1 2]] [2 2 2]] 

pero soy nuevo en Python y no sé cómo producir una tercera cuadrícula de valores z que tenga este aspecto:

 z = [[Nan 15 Nan] [14 16 18] [17 Nan 13]] 

Reemplazar a Nan con 0 estaría bien; Mi principal problema es crear la matriz 2D en primer lugar. ¡Gracias de antemano por tu ayuda!

Suponiendo que los valores x e y en su archivo se correspondan directamente con los índices (como lo hacen en su ejemplo), puede hacer algo similar a esto:

 import numpy as np x = [0, 0, 1, 1, 2, 2] y = [1, 2, 0, 1, 1, 2] z = [14, 17, 15, 16, 18, 13] z_array = np.nan * np.empty((3,3)) z_array[y, x] = z print z_array 

Cuyos rendimientos:

 [[ nan 15. nan] [ 14. 16. 18.] [ 17. nan 13.]] 

Para matrices grandes, esto será mucho más rápido que el bucle explícito sobre las coordenadas.


Tratar con entrada x & y no uniforme

Si ha muestreado regularmente los puntos x e y, entonces puede convertirlos a índices de cuadrícula restando la “esquina” de su cuadrícula (es decir, x0 y y0 ), dividiendo por el espaciado de la celda, y convirtiéndolos en ints. A continuación, puede utilizar el método anterior o en cualquiera de las otras respuestas.

Como ejemplo general:

 i = ((y - y0) / dy).astype(int) j = ((x - x0) / dx).astype(int) grid[i,j] = z 

Sin embargo, hay un par de trucos que puede utilizar si sus datos no están espaciados regularmente.

Digamos que tenemos los siguientes datos:

 import numpy as np import matplotlib.pyplot as plt np.random.seed(1977) x, y, z = np.random.random((3, 10)) fig, ax = plt.subplots() scat = ax.scatter(x, y, c=z, s=200) fig.colorbar(scat) ax.margins(0.05) 

introduzca la descripción de la imagen aquí

Que queremos poner en una grilla regular de 10×10:

introduzca la descripción de la imagen aquí

En realidad podemos usar / abuse np.histogram2d para esto. En lugar de recuentos, haremos que agregue el valor de cada punto que cae en una celda. Es más fácil hacer esto especificando weights=z, normed=False .

 import numpy as np import matplotlib.pyplot as plt np.random.seed(1977) x, y, z = np.random.random((3, 10)) # Bin the data onto a 10x10 grid # Have to reverse x & y due to row-first indexing zi, yi, xi = np.histogram2d(y, x, bins=(10,10), weights=z, normed=False) zi = np.ma.masked_equal(zi, 0) fig, ax = plt.subplots() ax.pcolormesh(xi, yi, zi, edgecolors='black') scat = ax.scatter(x, y, c=z, s=200) fig.colorbar(scat) ax.margins(0.05) plt.show() 

introduzca la descripción de la imagen aquí

Sin embargo, si tenemos una gran cantidad de puntos, algunos contenedores tendrán más de un punto. El argumento de weights a np.histogram simplemente agrega los valores. Probablemente no sea lo que quieres en este caso. No obstante, podemos obtener la media de los puntos que caen en cada celda al dividirlos por los conteos.

Entonces, por ejemplo, digamos que tenemos 50 puntos:

 import numpy as np import matplotlib.pyplot as plt np.random.seed(1977) x, y, z = np.random.random((3, 50)) # Bin the data onto a 10x10 grid # Have to reverse x & y due to row-first indexing zi, yi, xi = np.histogram2d(y, x, bins=(10,10), weights=z, normed=False) counts, _, _ = np.histogram2d(y, x, bins=(10,10)) zi = zi / counts zi = np.ma.masked_invalid(zi) fig, ax = plt.subplots() ax.pcolormesh(xi, yi, zi, edgecolors='black') scat = ax.scatter(x, y, c=z, s=200) fig.colorbar(scat) ax.margins(0.05) plt.show() 

introduzca la descripción de la imagen aquí

Con un gran número de puntos, este método exacto se volverá lento (y puede acelerarse fácilmente), pero es suficiente para cualquier cosa menor que ~ 1e6 puntos.

Kezzos me ganó, pero tenía un enfoque similar,

 x = np.array([0,0,1,1,2,2]) y = np.array([1,2,0,1,1,2]) z = np.array([14,17,15,16,18,13]) Z = np.zeros((3,3)) for i,j in enumerate(zip(x,y)): Z[j] = z[i] Z[np.where(Z==0)] = np.nan 

Podrías probar algo como:

 import numpy as np x = [0, 0, 1, 1, 2, 2] y = [1, 2, 0, 1, 1, 2] z = [14, 17, 15, 16, 18, 13] arr = np.zeros((3,3)) yx = zip(y,x) for i, coord in enumerate(yx): arr[coord] = z[i] print arr >>> [[ 0. 15. 0.] [ 14. 16. 18.] [ 17. 0. 13.]] 

Si tiene instalado scipy , podría aprovechar su módulo de matriz sparse . Obtenga los valores del archivo de texto con genfromtxt , y conecte esas ‘columnas’ directamente en un creador de matriz sparse .

 In [545]: txt=b"""xyz 0 1 14 0 2 17 1 0 15 1 1 16 2 1 18 2 2 13 """ In [546]: xyz=np.genfromtxt(txt.splitlines(),names=True,dtype=int) In [547]: sparse.coo_matrix((xyz['z'],(xyz['y'],xyz['x']))).A Out[547]: array([[ 0, 15, 0], [14, 16, 18], [17, 0, 13]]) 

Pero la z_array=np.zeros((3,3),int); z_array[xyz['y'],xyz['x']]=xyz['z'] de Joe z_array=np.zeros((3,3),int); z_array[xyz['y'],xyz['x']]=xyz['z'] z_array=np.zeros((3,3),int); z_array[xyz['y'],xyz['x']]=xyz['z'] es considerablemente más rápido.

Buenas respuestas por parte de otros. Pensé que esto podría ser un fragmento útil para alguien que podría necesitar esto.

 def make_grid(x, y, z): ''' Takes x, y, z values as lists and returns a 2D numpy array ''' dx = abs(np.sort(list(set(x)))[1] - np.sort(list(set(x)))[0]) dy = abs(np.sort(list(set(y)))[1] - np.sort(list(set(y)))[0]) i = ((x - min(x)) / dx).astype(int) # Longitudes j = ((y - max(y)) / dy).astype(int) # Latitudes grid = np.nan * np.empty((len(set(j)),len(set(i)))) grid[-j, i] = z # if using latitude and longitude (for WGS/West) return grid