Повторная выборка нерегулярно расположенных данных в регулярную сетку в Python - PullRequest
18 голосов
/ 05 октября 2010

Мне нужно сделать выборку 2D-данных в обычную сетку.

Вот как выглядит мой код:

import matplotlib.mlab as ml
import numpy as np

y = np.zeros((512,115))
x = np.zeros((512,115))

# Just random data for this test:
data = np.random.randn(512,115)

# filling the grid coordinates:    
for i in range(512):
    y[i,:]=np.arange(380,380+4*115,4)

for i in range(115):
    x[:,i] = np.linspace(-8,8,512)
    y[:,i] -=  np.linspace(-0.1,0.2,512)

# Defining the regular grid
y_i = np.arange(380,380+4*115,4)
x_i = np.linspace(-8,8,512)

resampled_data = ml.griddata(x,y,data,x_i,y_i)

(512,115) - это форма 2D-данных, и я уже установил mpl_toolkits.natgrid.

Моя проблема в том, что я возвращаю замаскированный массив, где большинство записей - это nan, а не массив, который в основном состоит из обычных записей и просто nan на границах.

Может ли кто-нибудь указать мне на то, что я делаю неправильно?

Спасибо!

1 Ответ

65 голосов
/ 06 октября 2010

Сравнивая ваш пример кода с заголовком вашего вопроса, я думаю, вы немного запутались ...

В вашем примере кода вы создаете регулярно привязанные к сетке случайные данные, а затем передискретизируете их в другую регулярную сетку . У вас нет нестандартных данных в вашем примере ...

(Кроме того, код не запускается как есть, и вам следует изучить meshgrid, а не выполнять циклический анализ для создания ваших сеток x & y.)

Если вы хотите повторно сэмплировать уже регулярно выбранную сетку, как вы делаете в своем примере, есть более эффективные методы, чем griddata или что-либо, что я собираюсь описать ниже. (scipy.ndimage.map_coordinates будет хорошо подходит для вашей проблемы, в этом случае.)

Однако, исходя из вашего вопроса, похоже, что у вас есть данные с нерегулярным интервалом, которые вы хотите интерполировать в регулярную сетку.

В этом случае у вас могут быть такие моменты:

import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

# Bounds and number of the randomly generated data points
ndata = 20
xmin, xmax = -8, 8
ymin, ymax = 380, 2428

# Generate random data
x = np.random.randint(xmin, xmax, ndata)
y = np.random.randint(ymin, ymax, ndata)
z = np.random.random(ndata)

# Plot the random data points
plt.scatter(x,y,c=z)
plt.axis([xmin, xmax, ymin, ymax])
plt.colorbar()
plt.show()

Randomly generated data

Затем вы можете интерполировать данные, как вы делали раньше ... (Продолжение из фрагмента кода выше ...)

# Size of regular grid
ny, nx = 512, 115

# Generate a regular grid to interpolate the data.
xi = np.linspace(xmin, xmax, nx)
yi = np.linspace(ymin, ymax, ny)
xi, yi = np.meshgrid(xi, yi)

# Interpolate using delaunay triangularization 
zi = mlab.griddata(x,y,z,xi,yi)

# Plot the results
plt.figure()
plt.pcolormesh(xi,yi,zi)
plt.scatter(x,y,c=z)
plt.colorbar()
plt.axis([xmin, xmax, ymin, ymax])
plt.show()

Poorly interpolated data

Тем не менее, вы заметите, что вы получаете много артефактов в сетке. Это связано с тем, что ваши координаты х колеблются от -8 до 8, а координаты у колеблются от ~ 300 до ~ 2500. Алгоритм интерполяции пытается сделать вещи изотропными, в то время как вы можете захотеть сильно анизотропную интерполяцию (чтобы она выглядела изотропной при построении сетки).

Чтобы исправить это, вам нужно создать новую систему координат, чтобы выполнить интерполяцию. Единого правильного способа сделать это не существует. То, что я использую ниже, будет работать, но «лучший» способ сильно зависит от того, что на самом деле представляют ваши данные.

(Другими словами, используйте то, что вы знаете о системе, которую измеряют ваши данные, чтобы решить, как это сделать. Это всегда верно с интерполяцией! Вы не должны интерполировать, если вы не знают, как должен выглядеть результат , и достаточно знакомы с алгоритмом интерполяции, чтобы использовать эту априорную информацию в ваших интересах !! Есть также гораздо более гибкие алгоритмы интерполяции, чем триангуляция Делоне, которую использует griddata по умолчанию тоже, но для простого примера это нормально ...)

В любом случае, один из способов сделать это - изменить масштаб координат x и y так, чтобы они находились примерно в одинаковых величинах. В этом случае. мы изменим их масштаб с 0 до 1 ... (простите строковый код спагетти ... я просто намерен привести это в пример ...)

# (Continued from examples above...)
# Normalize coordinate system
def normalize_x(data):
    data = data.astype(np.float)
    return (data - xmin) / (xmax - xmin)

def normalize_y(data):
    data = data.astype(np.float)
    return (data - ymin) / (ymax - ymin)

x_new, xi_new = normalize_x(x), normalize_x(xi)
y_new, yi_new = normalize_y(y), normalize_y(yi)

# Interpolate using delaunay triangularization 
zi = mlab.griddata(x_new, y_new, z, xi_new, yi_new)

# Plot the results
plt.figure()
plt.pcolormesh(xi,yi,zi)
plt.scatter(x,y,c=z)
plt.colorbar()
plt.axis([xmin, xmax, ymin, ymax])
plt.show()

Data interpolated in a normalized coordinate system

Надеюсь, это поможет, во всяком случае ... Извините за длину ответа!

...