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!
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.
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)
Das wollen wir in ein reguläres 10x10 Raster setzen:
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()
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()
Bei sehr vielen Punkten wird diese exakte Methode langsam (und kann leicht beschleunigt werden), reicht jedoch für weniger als ~ 1e6 Punkte aus.
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.]]
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
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.
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