From c4a43251bc08dd297fc2c89a05409a6d34a924cb Mon Sep 17 00:00:00 2001 From: tv3141 Date: Thu, 18 May 2017 12:10:48 +0100 Subject: [PATCH 1/4] Use faster np.average if nothing is masked. --- lib/iris/experimental/regrid.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index 021d0ce3e2..da3b068a32 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -384,21 +384,24 @@ def _weighted_mean_with_mdtol(data, weights, axis=None, mdtol=0): Numpy array (possibly masked) or scalar. """ - res = ma.average(data, weights=weights, axis=axis) - if ma.isMaskedArray(data) and mdtol < 1: - weights_total = weights.sum(axis=axis) - masked_weights = weights.copy() - masked_weights[~ma.getmaskarray(data)] = 0 - masked_weights_total = masked_weights.sum(axis=axis) - frac_masked = np.true_divide(masked_weights_total, weights_total) - mask_pt = frac_masked > mdtol - if np.any(mask_pt): - if np.isscalar(res): - res = ma.masked - elif ma.isMaskedArray(res): - res.mask |= mask_pt - else: - res = ma.masked_array(res, mask=mask_pt) + if ma.is_masked(data): + res = ma.average(data, weights=weights, axis=axis, returned=True) + if mdtol < 1: + weights_total = weights.sum(axis=axis) + masked_weights = weights.copy() + masked_weights[~ma.getmaskarray(data)] = 0 + masked_weights_total = masked_weights.sum(axis=axis) + frac_masked = np.true_divide(masked_weights_total, weights_total) + mask_pt = frac_masked > mdtol + if np.any(mask_pt): + if np.isscalar(res): + res = ma.masked + elif ma.isMaskedArray(res): + res.mask |= mask_pt + else: + res = ma.masked_array(res, mask=mask_pt) + else: + res = np.average(data, weights=weights, axis=axis) return res From 3c4cb5add1e11d04ed263661f1bc2c5f4f42fa64 Mon Sep 17 00:00:00 2001 From: tv3141 Date: Thu, 18 May 2017 12:13:33 +0100 Subject: [PATCH 2/4] Get weights sum from ma.average. --- lib/iris/experimental/regrid.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index da3b068a32..d75688c5e4 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -385,13 +385,11 @@ def _weighted_mean_with_mdtol(data, weights, axis=None, mdtol=0): """ if ma.is_masked(data): - res = ma.average(data, weights=weights, axis=axis, returned=True) + res, unmasked_weights_sum = ma.average(data, weights=weights, + axis=axis, returned=True) if mdtol < 1: - weights_total = weights.sum(axis=axis) - masked_weights = weights.copy() - masked_weights[~ma.getmaskarray(data)] = 0 - masked_weights_total = masked_weights.sum(axis=axis) - frac_masked = np.true_divide(masked_weights_total, weights_total) + weights_sum = weights.sum(axis=axis) + frac_masked = 1 - np.true_divide(unmasked_weights_sum, weights_sum) mask_pt = frac_masked > mdtol if np.any(mask_pt): if np.isscalar(res): From 2cd91f93e5b87c8856dc3119cfed7d1f4e043f09 Mon Sep 17 00:00:00 2001 From: tv3141 Date: Fri, 4 Aug 2017 16:34:00 +0100 Subject: [PATCH 3/4] Add old function for comparison. --- lib/iris/experimental/regrid.py | 58 +++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index d75688c5e4..271f9e59dd 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -18,7 +18,6 @@ Regridding functions. """ - from __future__ import (absolute_import, division, print_function) from six.moves import (filter, input, map, range, zip) # noqa import six @@ -350,7 +349,59 @@ def _get_bounds_in_units(coord, units, dtype): return coord.units.convert(coord.bounds.astype(dtype), units).astype(dtype) -def _weighted_mean_with_mdtol(data, weights, axis=None, mdtol=0): +def _weighted_mean_with_mdtol_old(data, weights, axis=None, mdtol=0): + """ + Return the weighted mean of an array over the specified axis + using the provided weights (if any) and a permitted fraction of + masked data. + + Args: + + * data (array-like): + Data to be averaged. + + * weights (array-like): + An array of the same shape as the data that specifies the contribution + of each corresponding data element to the calculated mean. + + Kwargs: + + * axis (int or tuple of ints): + Axis along which the mean is computed. The default is to compute + the mean of the flattened array. + + * mdtol (float): + Tolerance of missing data. The value returned in each element of the + returned array will be masked if the fraction of masked data exceeds + mdtol. This fraction is weighted by the `weights` array if one is + provided. mdtol=0 means no missing data is tolerated + while mdtol=1 will mean the resulting element will be masked if and + only if all the contributing elements of data are masked. + Defaults to 0. + + Returns: + Numpy array (possibly masked) or scalar. + + """ + res = ma.average(data, weights=weights, axis=axis) + if ma.isMaskedArray(data) and mdtol < 1: + weights_total = weights.sum(axis=axis) + masked_weights = weights.copy() + masked_weights[~ma.getmaskarray(data)] = 0 + masked_weights_total = masked_weights.sum(axis=axis) + frac_masked = np.true_divide(masked_weights_total, weights_total) + mask_pt = frac_masked > mdtol + if np.any(mask_pt): + if np.isscalar(res): + res = ma.masked + elif ma.isMaskedArray(res): + res.mask |= mask_pt + else: + res = ma.masked_array(res, mask=mask_pt) + return res + + +def _weighted_mean_with_mdtol_new(data, weights, axis=None, mdtol=0): """ Return the weighted mean of an array over the specified axis using the provided weights (if any) and a permitted fraction of @@ -403,6 +454,9 @@ def _weighted_mean_with_mdtol(data, weights, axis=None, mdtol=0): return res +_weighted_mean_with_mdtol = _weighted_mean_with_mdtol_new + + def _regrid_area_weighted_array(src_data, x_dim, y_dim, src_x_bounds, src_y_bounds, grid_x_bounds, grid_y_bounds, From a1b485ea191c9118cfc072d4a130cf560e123ed1 Mon Sep 17 00:00:00 2001 From: tv3141 Date: Wed, 11 Oct 2017 14:01:23 +0100 Subject: [PATCH 4/4] Remove old function used for comparison. --- lib/iris/experimental/regrid.py | 57 +-------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/lib/iris/experimental/regrid.py b/lib/iris/experimental/regrid.py index 271f9e59dd..fadefe4598 100644 --- a/lib/iris/experimental/regrid.py +++ b/lib/iris/experimental/regrid.py @@ -349,59 +349,7 @@ def _get_bounds_in_units(coord, units, dtype): return coord.units.convert(coord.bounds.astype(dtype), units).astype(dtype) -def _weighted_mean_with_mdtol_old(data, weights, axis=None, mdtol=0): - """ - Return the weighted mean of an array over the specified axis - using the provided weights (if any) and a permitted fraction of - masked data. - - Args: - - * data (array-like): - Data to be averaged. - - * weights (array-like): - An array of the same shape as the data that specifies the contribution - of each corresponding data element to the calculated mean. - - Kwargs: - - * axis (int or tuple of ints): - Axis along which the mean is computed. The default is to compute - the mean of the flattened array. - - * mdtol (float): - Tolerance of missing data. The value returned in each element of the - returned array will be masked if the fraction of masked data exceeds - mdtol. This fraction is weighted by the `weights` array if one is - provided. mdtol=0 means no missing data is tolerated - while mdtol=1 will mean the resulting element will be masked if and - only if all the contributing elements of data are masked. - Defaults to 0. - - Returns: - Numpy array (possibly masked) or scalar. - - """ - res = ma.average(data, weights=weights, axis=axis) - if ma.isMaskedArray(data) and mdtol < 1: - weights_total = weights.sum(axis=axis) - masked_weights = weights.copy() - masked_weights[~ma.getmaskarray(data)] = 0 - masked_weights_total = masked_weights.sum(axis=axis) - frac_masked = np.true_divide(masked_weights_total, weights_total) - mask_pt = frac_masked > mdtol - if np.any(mask_pt): - if np.isscalar(res): - res = ma.masked - elif ma.isMaskedArray(res): - res.mask |= mask_pt - else: - res = ma.masked_array(res, mask=mask_pt) - return res - - -def _weighted_mean_with_mdtol_new(data, weights, axis=None, mdtol=0): +def _weighted_mean_with_mdtol(data, weights, axis=None, mdtol=0): """ Return the weighted mean of an array over the specified axis using the provided weights (if any) and a permitted fraction of @@ -454,9 +402,6 @@ def _weighted_mean_with_mdtol_new(data, weights, axis=None, mdtol=0): return res -_weighted_mean_with_mdtol = _weighted_mean_with_mdtol_new - - def _regrid_area_weighted_array(src_data, x_dim, y_dim, src_x_bounds, src_y_bounds, grid_x_bounds, grid_y_bounds,