{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Parameter estimation using ordinal data" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "This Notebook explains the use of ordinal data for parameter estimation, as described in [Schmiester et al. (2020)](https://doi.org/10.1007/s00285-020-01522-w) and [Schmiester et al. (2021)](https://doi.org/10.1093/bioinformatics/btab512). \n", "An example model is provided in `pypesto/doc/example/example_ordinal`.\n", "\n", "Ordinal data is defined as the data for which the mutual ordering of the measurements is known. The implementation allows for indistinguishable measurements, i.e. multiple measurements which cannot be ordinally distinguished from each other and are part of the same ordinal level.\n", "\n", "For the integration of ordinal data, we employ the optimal scaling approach. In this approach, each ordinal datapoint is defined as being part of a category, where the mutual ordering of categories of the same observable is known. The category interval bounds are numerically optimized and quantitative surrogate measurements are calculated to represent the ordinal measurements. This constitutes the inner subproblem of the hierarchical optimization problem.\n", "\n", "Details on the optimal scaling approach can be found in Shepard, 1962 (https://doi.org/10.1007/BF02289621).\n", "Details on the application of the gradient-based optimal scaling approach to mechanistic modeling\n", "with ordinal data can be found in Schmiester et al. 2020 (https://doi.org/10.1007/s00285-020-01522-w)\n", "and Schmiester et al. 2021 (https://doi.org/10.1093/bioinformatics/btab512)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Import model from the petab_problem" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import petab\n", "\n", "import pypesto\n", "import pypesto.logging\n", "import pypesto.optimize as optimize\n", "from pypesto.hierarchical.ordinal import OrdinalInnerSolver\n", "from pypesto.petab import PetabImporter\n", "from pypesto.visualize import plot_categories_from_pypesto_result" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "To use ordinal data for parameter estimation, in pyPESTO we use the optimal scaling approach as in the referenced papers. Since the optimal scaling approach is implemented in the hierarchical manner, it requires us to specify `hierarchical=True` when importing the `petab_problem`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Visualization table not available. Skipping.\n" ] } ], "source": [ "petab_folder = \"./example_ordinal/\"\n", "yaml_file = \"example_ordinal.yaml\"\n", "\n", "petab_problem = petab.Problem.from_yaml(petab_folder + yaml_file)\n", "\n", "importer = PetabImporter(petab_problem, hierarchical=True)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `petab_problem` has to be specified in the usual PEtab formulation. The ordinal measurements have to be specified in the `measurement.tsv` file by adding `ordinal` in the `measurementType` column, and the ordering of measurements has to be specified in the `measurementCategory` column by assigning each measurement to a category:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | observableId | \n", "preequilibrationConditionId | \n", "simulationConditionId | \n", "measurement | \n", "time | \n", "observableParameters | \n", "noiseParameters | \n", "observableTransformation | \n", "noiseDistribution | \n", "measurementType | \n", "measurementCategory | \n", "
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | \n", "Activity | \n", "NaN | \n", "Inhibitor_0 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "2 | \n", "
| 1 | \n", "Activity | \n", "NaN | \n", "Inhibitor_3 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "2 | \n", "
| 2 | \n", "Activity | \n", "NaN | \n", "Inhibitor_10 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "
| 3 | \n", "Activity | \n", "NaN | \n", "Inhibitor_25 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "
| 4 | \n", "Activity | \n", "NaN | \n", "Inhibitor_35 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "2 | \n", "
| 5 | \n", "Activity | \n", "NaN | \n", "Inhibitor_50 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 6 | \n", "Activity | \n", "NaN | \n", "Inhibitor_75 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 7 | \n", "Activity | \n", "NaN | \n", "Inhibitor_100 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 8 | \n", "Activity | \n", "NaN | \n", "Inhibitor_300 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 9 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_0 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 10 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_3 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 11 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_10 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "1 | \n", "
| 12 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_25 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "2 | \n", "
| 13 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_35 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "2 | \n", "
| 14 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_50 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "
| 15 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_75 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "
| 16 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_100 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "
| 17 | \n", "Ybar | \n", "NaN | \n", "Inhibitor_300 | \n", "0 | \n", "5 | \n", "NaN | \n", "1 | \n", "lin | \n", "normal | \n", "ordinal | \n", "3 | \n", "