{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Angular data\n", "Sometimes we are interested in evaluating angular forecasts, such as a wind direction forecast against wind direction observations. \n", "\n", "Several metrics in `scores` can be used to evaluate angular forecasts expressed in degrees. If the `is_angular` argument is available in a metric, then that function can be used with angular data and it will handle the discontinuity that occurs between 360 degrees and 0. Simply set `is_angular=True`. It does this by calculating the length of the smaller of the two explementary angles between the two sources of data (e.g., forecast and observed).\n", "\n", "If your data is in radians, you can convert it to degrees my multiplying your data by 180/pi (you can use `numpy.pi`)." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "from scores.continuous import mae\n", "\n", "import numpy as np\n", "import xarray as xr\n", "\n", "np.random.seed(0) # set the seed to make notebook reproducible" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "fcst = xr.DataArray(\n", " data=np.random.random_sample((1000, 1000)) * 360, \n", " dims=[\"space\", \"time\"], \n", " coords=[np.arange(0, 1000), np.arange(0, 1000)]\n", ")\n", "obs = xr.DataArray(\n", " data=np.random.random_sample((1000, 1000)) * 360, \n", " dims=[\"space\", \"time\"], \n", " coords=[np.arange(0, 1000), np.arange(0, 1000)]\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's calculate MAE with `angular=True`" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
<xarray.DataArray ()>\n",
"array(89.9521687)<xarray.DataArray ()>\n",
"array(120.03938622)