From 63332753a35e1e6bdea380c6c57ab91d1e5d4556 Mon Sep 17 00:00:00 2001 From: "j.niesser" Date: Tue, 28 Nov 2023 11:38:11 +0100 Subject: [PATCH 1/3] add more documentation --- How to adapt PeakPerformance to your data.md | 19 +++ .../Ex2_Custom_Use_of_PeakPerformance.ipynb | 123 ++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 How to adapt PeakPerformance to your data.md create mode 100644 notebooks/Ex2_Custom_Use_of_PeakPerformance.ipynb diff --git a/How to adapt PeakPerformance to your data.md b/How to adapt PeakPerformance to your data.md new file mode 100644 index 0000000..f48f247 --- /dev/null +++ b/How to adapt PeakPerformance to your data.md @@ -0,0 +1,19 @@ +# How to adapt PeakPerformance to your methods / data +If your data shows a lack of fit when using the default models and prior probability distributions (priors) implemented in PeakPerformance, there are two main scenarios which differ with regards to the action required: + 1. An implemented model should be able to fit your peak data, but it does not converge properly. + 2. No currently implemented model is able to fit your peak data. + +## Scenario 1: Update the model priors +Open the `pipeline.py` file (containing the `pipeline` module) and search for functions starting with "define_". These will be the functions defining and returning a model object. Search for the function creating the model that should be able to fit your data and check the priors for its parameters. An easy way to visualize them is using the `stats` module from the `scipy` package in a seperate notebook and plotting the priors for an example peak of yours. Most likely, you will find that one or more priors do not represent your data well, e.g. the noise prior since that is highly dependent on the experimental method utilized to obtain your data in the first place. If you find priors that improve the model fit, just override the priors in the `pipeline` module. Be aware, though, that they will be overwritten by updates, so you should save them elsewhere and re-apply them when necessary. + +## Scenario 2: Implement another model +To implement a new model to PeakPerformance, you will need to create the following functions: + - in the `models` module: a function to define your model calling upon a separate function defining the posterior probablity distribution + - optional: create unit tests for your model in `test_models.py` + + +Additionally, you will need to update the following code segments: + - in the `models` module: update the ModelType class with your model + - in the `pipeline` module: + - add your model to if-statement around the model definition in the `pipeline_loop()` function + - add your model to the `selection_loop()` function diff --git a/notebooks/Ex2_Custom_Use_of_PeakPerformance.ipynb b/notebooks/Ex2_Custom_Use_of_PeakPerformance.ipynb new file mode 100644 index 0000000..258f453 --- /dev/null +++ b/notebooks/Ex2_Custom_Use_of_PeakPerformance.ipynb @@ -0,0 +1,123 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example 2: Directly access PeakPerformance's functions to create a custom pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas\n", + "import numpy as np\n", + "import arviz as az\n", + "from pathlib import Path\n", + "from peak_performance import pipeline as pl, models, plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define your time series, e.g. by giving a path to the raw data file und loading it." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "path = Path(\".\").absolute().parent / \"example\" / \"A1t1R1Part2_110_109.9_110.1.npy\"\n", + "timeseries = np.load(path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Decide on a model featured in PeakPerformance and create one based on the time series. \n", + "E.g. for a normally distributed model:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "pmodel = models.define_model_skew(\n", + " time=timeseries[0],\n", + " intensity=timeseries[1]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sample the model with an appropriate number of tuning samples and draws." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "idata = pl.sampling(pmodel, tune=6000, draws=2000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define a path for the results plot and its name (identifier), then use e.g. the plots.plot_posterior() function to plot the posterior samples against the raw data. For other plots, check out the plots module or the ArviZ documentation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "path_result = Path(r\"\")\n", + "\n", + "plots.plot_posterior(\n", + " identifier=\"test_plot\",\n", + " time=timeseries[0],\n", + " intensity=timeseries[1],\n", + " path=path_result,\n", + " idata=idata,\n", + " discarded=False,\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "nutpie_env2", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From e145fc7610c616cc295fa2700634ea8d444a2382 Mon Sep 17 00:00:00 2001 From: "j.niesser" Date: Tue, 28 Nov 2023 11:48:44 +0100 Subject: [PATCH 2/3] update exmple screenshots and pre-commit changes --- How to adapt PeakPerformance to your data.md | 4 ++-- notebooks/model_selection_example.png | Bin 10361 -> 10531 bytes notebooks/pipeline_example.png | Bin 11936 -> 12791 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/How to adapt PeakPerformance to your data.md b/How to adapt PeakPerformance to your data.md index f48f247..414a9b4 100644 --- a/How to adapt PeakPerformance to your data.md +++ b/How to adapt PeakPerformance to your data.md @@ -7,12 +7,12 @@ If your data shows a lack of fit when using the default models and prior probabi Open the `pipeline.py` file (containing the `pipeline` module) and search for functions starting with "define_". These will be the functions defining and returning a model object. Search for the function creating the model that should be able to fit your data and check the priors for its parameters. An easy way to visualize them is using the `stats` module from the `scipy` package in a seperate notebook and plotting the priors for an example peak of yours. Most likely, you will find that one or more priors do not represent your data well, e.g. the noise prior since that is highly dependent on the experimental method utilized to obtain your data in the first place. If you find priors that improve the model fit, just override the priors in the `pipeline` module. Be aware, though, that they will be overwritten by updates, so you should save them elsewhere and re-apply them when necessary. ## Scenario 2: Implement another model -To implement a new model to PeakPerformance, you will need to create the following functions: +To implement a new model to PeakPerformance, you will need to create the following functions: - in the `models` module: a function to define your model calling upon a separate function defining the posterior probablity distribution - optional: create unit tests for your model in `test_models.py` -Additionally, you will need to update the following code segments: +Additionally, you will need to update the following code segments: - in the `models` module: update the ModelType class with your model - in the `pipeline` module: - add your model to if-statement around the model definition in the `pipeline_loop()` function diff --git a/notebooks/model_selection_example.png b/notebooks/model_selection_example.png index 9ea78bd84fa668e2b3e3100ce1d893b010839284..6dd93c49c095099f05d4dca37e0c721106a079c2 100644 GIT binary patch literal 10531 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 R5M|xOf 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 literal 10361 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 diff --git a/notebooks/pipeline_example.png b/notebooks/pipeline_example.png index f0236e151634a6638587946dc2e22524bfd82327..d8d44909ee35cb9239190fcc3f059925d43dfa5a 100644 GIT binary patch literal 12791 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 Date: Thu, 30 Nov 2023 17:17:26 +0100 Subject: [PATCH 3/3] Apply 1 suggestion(s) to 1 file(s) --- How to adapt PeakPerformance to your data.md | 29 ++++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/How to adapt PeakPerformance to your data.md b/How to adapt PeakPerformance to your data.md index 414a9b4..260b2c8 100644 --- a/How to adapt PeakPerformance to your data.md +++ b/How to adapt PeakPerformance to your data.md @@ -1,19 +1,30 @@ # How to adapt PeakPerformance to your methods / data If your data shows a lack of fit when using the default models and prior probability distributions (priors) implemented in PeakPerformance, there are two main scenarios which differ with regards to the action required: - 1. An implemented model should be able to fit your peak data, but it does not converge properly. - 2. No currently implemented model is able to fit your peak data. + +1. An implemented model should be able to fit your peak data, but it does not converge properly. +2. No currently implemented model is able to fit your peak data. ## Scenario 1: Update the model priors -Open the `pipeline.py` file (containing the `pipeline` module) and search for functions starting with "define_". These will be the functions defining and returning a model object. Search for the function creating the model that should be able to fit your data and check the priors for its parameters. An easy way to visualize them is using the `stats` module from the `scipy` package in a seperate notebook and plotting the priors for an example peak of yours. Most likely, you will find that one or more priors do not represent your data well, e.g. the noise prior since that is highly dependent on the experimental method utilized to obtain your data in the first place. If you find priors that improve the model fit, just override the priors in the `pipeline` module. Be aware, though, that they will be overwritten by updates, so you should save them elsewhere and re-apply them when necessary. +Open the `pipeline.py` file (containing the `pipeline` module) and search for functions starting with "define_". +These will be the functions defining and returning a model object. +Search for the function creating the model that should be able to fit your data and check the priors for its parameters. +An easy way to visualize them is using the `stats` module from the `scipy` package in a seperate notebook and plotting the priors for an example peak of yours. +Most likely, you will find that one or more priors do not represent your data well, e.g. the noise prior since that is highly dependent on the experimental method utilized to obtain your data in the first place. +If you find priors that improve the model fit, just override the priors in the `pipeline` module. +Be aware, though, that they will be overwritten by updates, so you should save them elsewhere and re-apply them when necessary. ## Scenario 2: Implement another model To implement a new model to PeakPerformance, you will need to create the following functions: - - in the `models` module: a function to define your model calling upon a separate function defining the posterior probablity distribution - - optional: create unit tests for your model in `test_models.py` + +- In the `models` module: a function to define your model calling upon a separate function defining the posterior probablity distribution. +- Optional: create unit tests for your model in `test_models.py`. +- Required by AGPL: Publish your changes open source, for example by uploading the modified code to a public GitHub project. We are also welcoming pull requests that make PeakPerformance more enjoyable to use for everybody. Additionally, you will need to update the following code segments: - - in the `models` module: update the ModelType class with your model - - in the `pipeline` module: - - add your model to if-statement around the model definition in the `pipeline_loop()` function - - add your model to the `selection_loop()` function + +- In the `models` module: update the ModelType class with your model. +- In the `pipeline` module: + - Add your model to if-statement around the model definition in the `pipeline_loop()` function. + - Add your model to the `selection_loop()` function. +- Required by AGPL: Publish your changes open source, for example by uploading the modified code to a public GitHub project. We are also welcoming pull requests that make PeakPerformance more enjoyable to use for everybody.