Bias Removal

Climate models can have biases relative to different verification datasets. Commonly, biases are removed by postprocessing before verification of forecasting skill. climpred provides convenience functions to do so.

[1]:
# linting
%load_ext nb_black
%load_ext lab_black
[2]:
import climpred
import xarray as xr
import matplotlib.pyplot as plt
from climpred import HindcastEnsemble
[3]:
hind = climpred.tutorial.load_dataset(
    "CESM-DP-SST"
)  # CESM-DPLE hindcast ensemble output.
obs = climpred.tutorial.load_dataset("ERSST")  # observations
hind["lead"].attrs["units"] = "years"

We begin by removing a mean climatology for the observations, since CESM-DPLE generates its anomalies over this same time period.

[4]:
obs = obs - obs.sel(time=slice("1964", "2014")).mean("time")
[5]:
hindcast = HindcastEnsemble(hind)
hindcast = hindcast.add_observations(obs)
hindcast.plot()
/Users/aaron.spring/Coding/climpred/climpred/utils.py:122: UserWarning: Assuming annual resolution due to numeric inits. Change init to a datetime if it is another resolution.
  warnings.warn(
[5]:
<AxesSubplot:xlabel='time', ylabel='SST'>
_images/bias_removal_7_2.png

The warming of the observations is similar to initialized.

Mean bias removal

Typically, bias depends on lead-time and therefore should therefore also be removed depending on lead-time.

[6]:
bias = hindcast.verify(metric="bias", comparison="e2o", dim=[], alignment="same_verifs")
[7]:
bias.SST.plot()
[7]:
<matplotlib.collections.QuadMesh at 0x7fb91960ffa0>
_images/bias_removal_12_1.png

Against observations, there is small cold bias in 1980 and 1990 initialization years and warm bias before and after.

[8]:
# lead-time dependant mean bias over all initializations is quite small but negative
mean_bias = bias.mean("init")
mean_bias.SST.plot()
[8]:
[<matplotlib.lines.Line2D at 0x7fb9196ba340>]
_images/bias_removal_14_1.png

Cross Validatation

To remove the mean bias quickly, the mean bias over all initializations is subtracted. For formally correct bias removal with cross validation, the given initialization is left out when subtracting the mean bias.

climpred wraps these functions in HindcastEnsemble.remove_bias(how='mean', cross_validate={bool}).

[9]:
hindcast.remove_bias(how="mean", cross_validate=True, alignment="same_verifs").plot()
plt.title("hindcast lead timeseries removed for unconditional mean bias")
plt.show()
_images/bias_removal_17_0.png

Skill

Distance-based accuracy metrics like (mse,rmse,nrmse,…) are sensitive to mean bias removal. Correlations like (pearson_r, spearman_r) are insensitive to bias correction.

[10]:
metric = "rmse"
hindcast.verify(metric=metric, comparison="e2o", dim="init", alignment="same_verifs")[
    "SST"
].plot(label="no bias correction")
hindcast.remove_bias(cross_validate=False, alignment="same_verifs").verify(
    metric=metric, comparison="e2o", dim="init", alignment="same_verifs"
).SST.plot(label="bias correction without cross validation")
hindcast.remove_bias(cross_validate=True, alignment="same_verifs").verify(
    metric=metric, comparison="e2o", dim="init", alignment="same_verifs"
).SST.plot(label="formally correct bias correction with cross validation")
plt.legend()
plt.title(f"{metric.upper()} SST evaluated against observations")
plt.show()
_images/bias_removal_20_0.png