Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scipy interpolation with masked data?

I am trying to interpolate a 2D array that contents masked data. I have used some of the SciPy module's methods available, including interp2d, bisplrep/bisplev, as well as RectBivariateSpline. As an additional information, my data is a regular array, which means that grids have the same dimension (in this case 1ºX1º).

Having said that, is there any way to interpolate avoiding masked data in an array with Python? I am still new using Python and NumPy/SciPy modules.

like image 942
hurrdrought Avatar asked Mar 04 '16 22:03

hurrdrought


1 Answers

You can actually use every function that accepts x, y, z (which is the case for interp2d and probably the others as well) with your masked data. But you need to explicitly create a mgrid:

z = ... # Your data
x, y = np.mgrid[0:z.shape[0], 0:z.shape[1]]

Then you need to delete all masked values in all of these coordinates:

x = x[~z.mask]
y = y[~z.mask]
z = z[~z.mask]

With these final x, y, z you can call every of your specified functions (that accepts incomplete grids, so RectBivariateSpline won't work). Notice however that some of these use interpolation boxes so if there is a too big region where you discarded the data because of your mask the interpolation will fail there (resulting in np.nan or 0). But you might tweak the parameters to compensate for that, if it happens.

For example:

data = np.random.randint(0, 10, (5,5))
mask = np.random.uniform(0,1,(5,5)) > 0.5
z = np.ma.array(data, mask=mask)
x, y = np.mgrid[0:z.shape[0], 0:z.shape[1]]
x1 = x[~z.mask]
y1 = y[~z.mask]
z1 = z[~z.mask]
interp2d(x1, y1, z1)(np.arange(z.shape[0]), np.arange(z.shape[1]))

array([[  1.1356716 ,   2.45313727,   3.77060294,   6.09790177, 9.31328935],
       [  3.91917937,   4.        ,   4.08082063,   3.98508121, 3.73406764],
       [ 42.1933738 ,  25.0966869 ,   8.        ,   0.        , 0.        ],
       [  1.55118338,   3.        ,   4.44881662,   4.73544593, 4.        ],
       [  5.        ,   8.        ,  11.        ,   9.34152525, 3.58619652]])

you can see the small area of 0's because the mask had there many masked values:

mask
array([[False,  True,  True,  True, False],
       [False, False,  True, False, False],
       [ True,  True, False,  True,  True],
       [False,  True, False,  True,  True],
       [False,  True, False, False,  True]], dtype=bool)

data
array([[2, 4, 4, 5, 5],
       [1, 4, 1, 3, 8],
       [9, 1, 8, 0, 9],
       [7, 2, 0, 3, 4],
       [9, 6, 0, 4, 4]])
like image 77
MSeifert Avatar answered Oct 13 '22 01:10

MSeifert