wake-up-neo.net

Python-Zahl: Erstellen Sie ein 2D-Array von Werten basierend auf Koordinaten

Ich habe eine Datei mit 3 Spalten, wobei die ersten beiden Koordinaten (x, y) und der dritte ein Wert (z) sind, der dieser Position entspricht. Hier ist ein kurzes Beispiel:

x y z
0 1 14
0 2 17
1 0 15
1 1 16
2 1 18
2 2 13

Ich möchte ein 2D-Array von Werten aus der dritten Zeile erstellen, basierend auf ihren x, y-Koordinaten in der Datei. Ich habe jede Spalte als einzelnes Array eingelesen und mit numpy.meshgrid Gitter mit x- und y-Werten erstellt.

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

aber ich bin neu in Python und weiß nicht, wie ich ein drittes Raster von z-Werten erzeugen soll, das so aussieht:

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

Das Ersetzen von Nan durch 0 ist ebenfalls in Ordnung. Mein Hauptproblem ist die Erstellung des 2D-Arrays. Vielen Dank im Voraus für Ihre Hilfe!

11
Aero

Angenommen, die Werte x und y in Ihrer Datei entsprechen direkt den Indizes (wie in Ihrem Beispiel), können Sie etwas Ähnliches tun:

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

Welche Erträge:

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

Bei großen Arrays ist dies viel schneller als die explizite Schleife über die Koordinaten.


Umgang mit ungleichmäßigen x & y-Eingaben

Wenn Sie regelmäßig x & y-Punkte abgetastet haben, können Sie diese in Rasterindizes konvertieren, indem Sie die "Ecke" Ihres Rasters (d. H. x0 und y0) subtrahieren, durch den Zellabstand dividieren und als Ints gießen. Sie können dann die obige Methode oder eine der anderen Antworten verwenden.

Als allgemeines Beispiel:

i = ((y - y0) / dy).astype(int)
j = ((x - x0) / dx).astype(int)

grid[i,j] = z

Es gibt jedoch einige Tricks, die Sie anwenden können, wenn Ihre Daten nicht regelmäßig verteilt sind.

Nehmen wir an, wir haben folgende Daten:

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)

enter image description here

Das wollen wir in ein reguläres 10x10 Raster setzen:

enter image description here

Wir können dafür np.histogram2d tatsächlich verwenden/missbrauchen. Anstatt zu zählen, addieren wir den Wert jedes Punktes, der in eine Zelle fällt. Dies geschieht am einfachsten durch Angabe von 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()

enter image description here

Wenn wir jedoch eine große Anzahl von Punkten haben, haben einige Fächer mehr als einen Punkt. Das Argument weights zu np.histogram fügt einfachdie Werte hinzu. Das ist wahrscheinlich nicht das, was Sie in diesem Fall wollen. Nichtsdestotrotz können wir den Mittelwert der Punkte, die in jede Zelle fallen, durch Teilen durch die Anzahl erhalten.

Nehmen wir zum Beispiel an, wir haben 50 Punkte:

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

enter image description here

Bei sehr vielen Punkten wird diese exakte Methode langsam (und kann leicht beschleunigt werden), reicht jedoch für weniger als ~ 1e6 Punkte aus.

25
Joe Kington

Sie könnten versuchen, etwas wie:

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.]]
4
kezzos

Kezzos schlug mich, aber ich hatte einen ähnlichen Ansatz,

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
4
Dave

Wenn Sie scipy installiert haben, können Sie das Matrixmodul sparse nutzen. Rufen Sie die Werte mit genfromtxt aus der Textdatei ab und fügen Sie diese 'Spalten' direkt in einen sparse-Matrixersteller ein.

In [545]: txt=b"""x y z
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]])

Aber Joes z_array=np.zeros((3,3),int); z_array[xyz['y'],xyz['x']]=xyz['z'] ist erheblich schneller.

2
hpaulj

Nette Antworten von anderen. Dachte, dies könnte ein nützlicher Ausschnitt für jemanden sein, der dies benötigt.

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
0
Solomon Vimal