From e5092d6968b3bbfcb2d78944f94229019316fc3b Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Wed, 29 Oct 2025 22:58:11 +0000 Subject: [PATCH 1/9] initialize new tuts --- tutorials/plot_04-PeriodicFitting.py | 93 ++++++++++++++++++++++++++++ tutorials/plot_06-Metrics.py | 62 +++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 tutorials/plot_04-PeriodicFitting.py create mode 100644 tutorials/plot_06-Metrics.py diff --git a/tutorials/plot_04-PeriodicFitting.py b/tutorials/plot_04-PeriodicFitting.py new file mode 100644 index 00000000..3907ea26 --- /dev/null +++ b/tutorials/plot_04-PeriodicFitting.py @@ -0,0 +1,93 @@ +""" +XX: Periodic Component Fitting +=============================== + +Choosing and using different modes for fitting the periodic component. +""" + +################################################################################################### + +# Import the model object +from specparam import SpectralModel + +# Import a utility to download and load example data +from specparam.utils.download import load_example_data + +################################################################################################### +# Periodic Fitting Approaches +# --------------------------- +# +# Words, words, words +# + +################################################################################################### + + + + +################################################################################################### +# Mathematical Description of the Periodic Component +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# To fit this periodic activity - the regions of power over above the aperiodic component, +# or 'peaks' - the model uses Gaussians. As we've seen, there can be multiple peaks in the model. +# +# Each Gaussian, :math:`n`, referred to as :math:`G(F)_n`, is of the form: +# +# .. math:: +# G(F)_n = a * exp (\frac{- (F - c)^2}{2 * w^2}) +# +# This describes each peak in terms of parameters `a`, `c` and `w`, where: +# +# - :math:`a` is the height of the peak, over and above the aperiodic component +# - :math:`c` is the center frequency of the peak +# - :math:`w` is the width of the peak +# - :math:`F` is the array of frequency values +# + + + +################################################################################################### +# Notes on Interpreting Peak Parameters +# ------------------------------------- +# +# Peak parameters are labeled as: +# +# - CF: center frequency of the extracted peak +# - PW: power of the peak, over and above the aperiodic component +# - BW: bandwidth of the extracted peak +# +# Note that the peak parameters that are returned are not exactly the same as the +# parameters of the Gaussians used internally to fit the peaks. +# +# Specifically: +# +# - CF is the exact same as mean parameter of the Gaussian +# - PW is the height of the model fit above the aperiodic component [1], +# which is not necessarily the same as the Gaussian height +# - BW is 2 * the standard deviation of the Gaussian [2] +# +# [1] Since the Gaussians are fit together, if any Gaussians overlap, +# than the actual height of the fit at a given point can only be assessed +# when considering all Gaussians. To be better able to interpret heights +# for individual peaks, we re-define the peak height as above, and label it +# as 'power', as the units of the input data are expected to be units of power. +# +# [2] Gaussian standard deviation is '1 sided', where as the returned BW is '2 sided'. +# + +################################################################################################### +# +# The underlying gaussian parameters are also available from the model object, +# in the ``gaussian_params_`` attribute. +# + + +################################################################################################### + + +################################################################################################### + + + +################################################################################################### \ No newline at end of file diff --git a/tutorials/plot_06-Metrics.py b/tutorials/plot_06-Metrics.py new file mode 100644 index 00000000..8cb38309 --- /dev/null +++ b/tutorials/plot_06-Metrics.py @@ -0,0 +1,62 @@ +""" +XX: Metrics & Model Evaluation +============================== + +An overview of metrics & model evaluation to examine model fit quality. +""" + +################################################################################################### +# Model Metrics +# ------------- +# +# In this tutorial, we will explore model metrics. +# +# The `specparam` module uses the term `metric` to refer to a measure that is computed that +# reflects something about the spectral model (but that is not computed as part of the model fit). +# +# + +################################################################################################### +# +# +# + +################################################################################################### +# Interpreting Model Fit Quality Measures +# --------------------------------------- +# +# After model fitting, some goodness of fit metrics are calculated to assist with assessing +# the quality of the model fits. It calculates both the model fit error, as the mean absolute +# error (MAE) between the full model fit (``modeled_spectrum_``) and the original power spectrum, +# as well as the R-squared correspondence between the original spectrum and the full model. +# + +# These scores can be used to assess how the model is performing. However interpreting these +# measures requires a bit of nuance. Model fitting is NOT optimized to minimize fit error / +# maximize r-squared at all costs. To do so typically results in fitting a large number of peaks, +# in a way that overfits noise, and only artificially reduces error / maximizes r-squared. +# +# The power spectrum model is therefore tuned to try and measure the aperiodic component +# and peaks in a parsimonious manner, and, fit the `right` model (meaning the right aperiodic +# component and the right number of peaks) rather than the model with the lowest error. +# +# Given this, while high error / low r-squared may indicate a poor model fit, very low +# error / high r-squared may also indicate a power spectrum that is overfit, in particular +# in which the peak parameters from the model may reflect overfitting by fitting too many peaks. +# +# We therefore recommend that, for a given dataset, initial explorations should involve +# checking both cases in which model fit error is particularly large, as well as when it +# is particularly low. These explorations can be used to pick settings that are suitable +# for running across a group. There are not universal settings that optimize this, and so +# it is left up to the user to choose settings appropriately to not under- or over-fit +# for a given modality / dataset / application. +# + + +################################################################################################### + + +################################################################################################### + + +################################################################################################### From 591816a265075fca560c3ddd9889a548edaafac9 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Wed, 29 Oct 2025 23:00:26 +0000 Subject: [PATCH 2/9] reorder tuts --- tutorials/{plot_06-GroupFits.py => plot_08-GroupFits.py} | 0 tutorials/{plot_07-TimeModels.py => plot_09-TimeModels.py} | 0 .../{plot_08-TroubleShooting.py => plot_10-TroubleShooting.py} | 0 .../{plot_09-FurtherAnalysis.py => plot_11-FurtherAnalysis.py} | 0 tutorials/{plot_10-Reporting.py => plot_12-Reporting.py} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tutorials/{plot_06-GroupFits.py => plot_08-GroupFits.py} (100%) rename tutorials/{plot_07-TimeModels.py => plot_09-TimeModels.py} (100%) rename tutorials/{plot_08-TroubleShooting.py => plot_10-TroubleShooting.py} (100%) rename tutorials/{plot_09-FurtherAnalysis.py => plot_11-FurtherAnalysis.py} (100%) rename tutorials/{plot_10-Reporting.py => plot_12-Reporting.py} (100%) diff --git a/tutorials/plot_06-GroupFits.py b/tutorials/plot_08-GroupFits.py similarity index 100% rename from tutorials/plot_06-GroupFits.py rename to tutorials/plot_08-GroupFits.py diff --git a/tutorials/plot_07-TimeModels.py b/tutorials/plot_09-TimeModels.py similarity index 100% rename from tutorials/plot_07-TimeModels.py rename to tutorials/plot_09-TimeModels.py diff --git a/tutorials/plot_08-TroubleShooting.py b/tutorials/plot_10-TroubleShooting.py similarity index 100% rename from tutorials/plot_08-TroubleShooting.py rename to tutorials/plot_10-TroubleShooting.py diff --git a/tutorials/plot_09-FurtherAnalysis.py b/tutorials/plot_11-FurtherAnalysis.py similarity index 100% rename from tutorials/plot_09-FurtherAnalysis.py rename to tutorials/plot_11-FurtherAnalysis.py diff --git a/tutorials/plot_10-Reporting.py b/tutorials/plot_12-Reporting.py similarity index 100% rename from tutorials/plot_10-Reporting.py rename to tutorials/plot_12-Reporting.py From 0b936da261c7afd9705f291c07b2fb38152c3922 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Wed, 29 Oct 2025 23:00:35 +0000 Subject: [PATCH 3/9] interim upd / move things --- tutorials/plot_01-ModelDescription.py | 96 ++------------------------ tutorials/plot_02-PSDModel.py | 35 ---------- tutorials/plot_04-ModelObject.py | 2 +- tutorials/plot_05-AperiodicFitting.py | 98 +++++++++++++++++++++++++-- tutorials/plot_10-TroubleShooting.py | 30 -------- 5 files changed, 101 insertions(+), 160 deletions(-) diff --git a/tutorials/plot_01-ModelDescription.py b/tutorials/plot_01-ModelDescription.py index 9a0133f3..e8dcb16c 100644 --- a/tutorials/plot_01-ModelDescription.py +++ b/tutorials/plot_01-ModelDescription.py @@ -2,7 +2,7 @@ 01: Model Description ===================== -A description of and introduction to the power spectrum model. +A description of and introduction to the spectral parameterization module. """ ################################################################################################### @@ -11,8 +11,8 @@ # # Welcome to the tutorials! # -# In this first tutorial, we will introduce an overview and description of power spectrum -# model, as well as visualizing some examples. +# In this first tutorial, we will introduce an overview and description of the +# spectral parameterization module, as well as visualizing some examples. # # Keep in mind as you go, that if you want more information that describes, motivates, and # justifies our modeling approach, you can also check out the associated @@ -29,15 +29,15 @@ # First, we will import and run some code to simulate some example power spectra, and # fit some power spectrum models to them, to use as examples. # -# For the purpose of this tutorial, you don't need to know how this code works -# yet, and can skip past reading the code itself. +# Note that for the purpose of this tutorial, you don't need to know exactly how this code works +# yet, as the details of what is happening will be clarified across the rest of the tutorials. # ################################################################################################### # sphinx_gallery_thumbnail_number = 5 -# Import required code for visualizing example models +# Import required code for simulating and visualizing example models from specparam import SpectralModel from specparam.sim import sim_power_spectrum from specparam.sim.utils import set_random_seed @@ -207,26 +207,6 @@ # to describe this component of the data. # -################################################################################################### -# Mathematical Description of the Periodic Component -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# To fit this periodic activity - the regions of power over above the aperiodic component, -# or 'peaks' - the model uses Gaussians. As we've seen, there can be multiple peaks in the model. -# -# Each Gaussian, :math:`n`, referred to as :math:`G(F)_n`, is of the form: -# -# .. math:: -# G(F)_n = a * exp (\frac{- (F - c)^2}{2 * w^2}) -# -# This describes each peak in terms of parameters `a`, `c` and `w`, where: -# -# - :math:`a` is the height of the peak, over and above the aperiodic component -# - :math:`c` is the center frequency of the peak -# - :math:`w` is the width of the peak -# - :math:`F` is the array of frequency values -# - ################################################################################################### # Aperiodic Component # ------------------- @@ -257,43 +237,6 @@ # Note that diagonal labels indicate unit-less measures (in neither units of frequency or power). # -################################################################################################### -# Mathematical Description of the Aperiodic Component -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# To fit the aperiodic component, we will use the function :math:`L`: -# -# .. math:: -# L(F) = b - \log(k + F^\chi) -# -# Note that this function is fit on the semi-log power spectrum, meaning linear frequencies -# and :math:`log_{10}` power values. -# -# In this formulation, the parameters :math:`b`, :math:`k`, and :math:`\chi` -# define the aperiodic component, as: -# -# - :math:`b` is the broadband 'offset' -# - :math:`k` is the 'knee' -# - :math:`\chi` is the 'exponent' of the aperiodic fit -# - :math:`F` is the array of frequency values -# -# Note that fitting the knee parameter is optional. If used, the knee parameter defines a -# 'bend' in the aperiodic `1/f` like component of the data. If not used, the 'knee' -# parameter is set to zero. -# -# This function form is technically described as a Lorentzian function. We use the option -# of adding a knee parameter, since even though neural data is often discussed in terms -# of having `1/f` activity, there is often not a single `1/f` characteristic, especially -# across broader frequency ranges. Therefore, using this function form allows for modeling -# bends in the power spectrum of the aperiodic component, if and when they occur. -# -# Note that if we were to want the equivalent function in linear power, using :math:`AP` -# to indicate the aperiodic component in linear spacing, it would be: -# -# .. math:: -# AP(F) = 10^b * \frac{1}{(k + F^\chi)} -# - ################################################################################################### # A Note on Logging # ~~~~~~~~~~~~~~~~~ @@ -316,33 +259,6 @@ # Plot the power spectrum model, in log-log space plot_annotated_model(fm1, plt_log=True) -################################################################################################### -# Relating Exponents to Power Spectrum Slope -# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# -# Another way to measure 1/f properties in neural power spectra is to measure the slope -# of the spectrum in log-log spacing, fitting a linear equation as: -# -# .. math:: -# L(log(F)) = aF + b -# -# Where: -# -# - :math:`a` is the power spectrum slope -# - :math:`b` is the offset -# - :math:`F` is the array of frequency values -# -# In this formulation, the data is considered in log-log space, meaning the frequency values -# are also in log space. Since 1/f is a straight line in log-log spacing, this approach captures -# 1/f activity. -# -# This is equivalent to the power spectrum model in this module, when fitting with no knee, -# with a direct relationship between the slope (:math:`a`) and the exponent (:math:`\chi`): -# -# .. math:: -# \chi = -a -# - ################################################################################################### # Fitting Knees # ~~~~~~~~~~~~~ diff --git a/tutorials/plot_02-PSDModel.py b/tutorials/plot_02-PSDModel.py index b00c1206..5d3056ce 100644 --- a/tutorials/plot_02-PSDModel.py +++ b/tutorials/plot_02-PSDModel.py @@ -177,41 +177,6 @@ print(template.format(error=err, exponent=exp, cfs=' & '.join(map(str, [round(cf, 2) for cf in cfs])))) -################################################################################################### -# Notes on Interpreting Peak Parameters -# ------------------------------------- -# -# Peak parameters are labeled as: -# -# - CF: center frequency of the extracted peak -# - PW: power of the peak, over and above the aperiodic component -# - BW: bandwidth of the extracted peak -# -# Note that the peak parameters that are returned are not exactly the same as the -# parameters of the Gaussians used internally to fit the peaks. -# -# Specifically: -# -# - CF is the exact same as mean parameter of the Gaussian -# - PW is the height of the model fit above the aperiodic component [1], -# which is not necessarily the same as the Gaussian height -# - BW is 2 * the standard deviation of the Gaussian [2] -# -# [1] Since the Gaussians are fit together, if any Gaussians overlap, -# than the actual height of the fit at a given point can only be assessed -# when considering all Gaussians. To be better able to interpret heights -# for individual peaks, we re-define the peak height as above, and label it -# as 'power', as the units of the input data are expected to be units of power. -# -# [2] Gaussian standard deviation is '1 sided', where as the returned BW is '2 sided'. -# - -################################################################################################### -# -# The underlying gaussian parameters are also available from the model object, -# in the ``gaussian_params_`` attribute. -# - ################################################################################################### # Compare the 'peak_params_' to the underlying gaussian parameters diff --git a/tutorials/plot_04-ModelObject.py b/tutorials/plot_04-ModelObject.py index 70460a18..27ca6e9d 100644 --- a/tutorials/plot_04-ModelObject.py +++ b/tutorials/plot_04-ModelObject.py @@ -1,5 +1,5 @@ """ -04: Exploring the model object +XX: Exploring the model object ============================== Further exploring the SpectralModel object, including algorithm settings and available methods. diff --git a/tutorials/plot_05-AperiodicFitting.py b/tutorials/plot_05-AperiodicFitting.py index 59221b26..c8a62fc8 100644 --- a/tutorials/plot_05-AperiodicFitting.py +++ b/tutorials/plot_05-AperiodicFitting.py @@ -14,8 +14,8 @@ from specparam.utils.download import load_example_data ################################################################################################### -# Aperiodic Fitting Approaches -# ---------------------------- +# Aperiodic Fit Modes +# ------------------- # # There are currently two approaches for fitting the aperiodic component: # @@ -40,6 +40,96 @@ # should be done using an extra parameter to capture this, using the 'knee' mode. # + + + + +################################################################################################### +# Relating Exponents to Power Spectrum Slope +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Another way to measure 1/f properties in neural power spectra is to measure the slope +# of the spectrum in log-log spacing, fitting a linear equation as: +# +# .. math:: +# L(log(F)) = aF + b +# +# Where: +# +# - :math:`a` is the power spectrum slope +# - :math:`b` is the offset +# - :math:`F` is the array of frequency values +# +# In this formulation, the data is considered in log-log space, meaning the frequency values +# are also in log space. Since 1/f is a straight line in log-log spacing, this approach captures +# 1/f activity. +# +# This is equivalent to the power spectrum model in this module, when fitting with no knee, +# with a direct relationship between the slope (:math:`a`) and the exponent (:math:`\chi`): +# +# .. math:: +# \chi = -a +# + + + + + +################################################################################################### +# Mathematical Description of the Aperiodic Component +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# To fit the aperiodic component, we will use the function :math:`L`: +# +# .. math:: +# L(F) = b - \log(k + F^\chi) +# +# Note that this function is fit on the semi-log power spectrum, meaning linear frequencies +# and :math:`log_{10}` power values. +# +# In this formulation, the parameters :math:`b`, :math:`k`, and :math:`\chi` +# define the aperiodic component, as: +# +# - :math:`b` is the broadband 'offset' +# - :math:`k` is the 'knee' +# - :math:`\chi` is the 'exponent' of the aperiodic fit +# - :math:`F` is the array of frequency values +# +# Note that fitting the knee parameter is optional. If used, the knee parameter defines a +# 'bend' in the aperiodic `1/f` like component of the data. If not used, the 'knee' +# parameter is set to zero. +# +# This function form is technically described as a Lorentzian function. We use the option +# of adding a knee parameter, since even though neural data is often discussed in terms +# of having `1/f` activity, there is often not a single `1/f` characteristic, especially +# across broader frequency ranges. Therefore, using this function form allows for modeling +# bends in the power spectrum of the aperiodic component, if and when they occur. +# +# Note that if we were to want the equivalent function in linear power, using :math:`AP` +# to indicate the aperiodic component in linear spacing, it would be: +# +# .. math:: +# AP(F) = 10^b * \frac{1}{(k + F^\chi)} +# + + + + + + + + + + + + + +################################################################################################### +# +# +# +# + ################################################################################################### # Fitting with an Aperiodic 'Knee' # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -119,8 +209,8 @@ # ################################################################################################### -# Choosing an Aperiodic Fitting Procedure -# --------------------------------------- +# Choosing an Aperiodic Fit Mode +# ------------------------------ # # It is important to choose the appropriate aperiodic fitting approach for your data. # diff --git a/tutorials/plot_10-TroubleShooting.py b/tutorials/plot_10-TroubleShooting.py index 072db700..aa45b7d2 100644 --- a/tutorials/plot_10-TroubleShooting.py +++ b/tutorials/plot_10-TroubleShooting.py @@ -68,36 +68,6 @@ # for different datasets. # -################################################################################################### -# Interpreting Model Fit Quality Measures -# --------------------------------------- -# -# After model fitting, some goodness of fit metrics are calculated to assist with assessing -# the quality of the model fits. It calculates both the model fit error, as the mean absolute -# error (MAE) between the full model fit (``modeled_spectrum_``) and the original power spectrum, -# as well as the R-squared correspondence between the original spectrum and the full model. -# -# These scores can be used to assess how the model is performing. However interpreting these -# measures requires a bit of nuance. Model fitting is NOT optimized to minimize fit error / -# maximize r-squared at all costs. To do so typically results in fitting a large number of peaks, -# in a way that overfits noise, and only artificially reduces error / maximizes r-squared. -# -# The power spectrum model is therefore tuned to try and measure the aperiodic component -# and peaks in a parsimonious manner, and, fit the `right` model (meaning the right aperiodic -# component and the right number of peaks) rather than the model with the lowest error. -# -# Given this, while high error / low r-squared may indicate a poor model fit, very low -# error / high r-squared may also indicate a power spectrum that is overfit, in particular -# in which the peak parameters from the model may reflect overfitting by fitting too many peaks. -# -# We therefore recommend that, for a given dataset, initial explorations should involve -# checking both cases in which model fit error is particularly large, as well as when it -# is particularly low. These explorations can be used to pick settings that are suitable -# for running across a group. There are not universal settings that optimize this, and so -# it is left up to the user to choose settings appropriately to not under- or over-fit -# for a given modality / dataset / application. -# - ################################################################################################### # Reducing Overfitting # -------------------- From a482af7f65aebf8baca3a3e20b172f052b23afa1 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Wed, 29 Oct 2025 23:35:45 +0000 Subject: [PATCH 4/9] finish re-ordering --- tutorials/plot_04-PeriodicFitting.py | 2 +- tutorials/plot_06-Metrics.py | 2 +- tutorials/{plot_04-ModelObject.py => plot_07-ModelObject.py} | 2 +- tutorials/plot_08-GroupFits.py | 2 +- tutorials/plot_09-TimeModels.py | 2 +- tutorials/plot_10-TroubleShooting.py | 2 +- tutorials/plot_11-FurtherAnalysis.py | 2 +- tutorials/plot_12-Reporting.py | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename tutorials/{plot_04-ModelObject.py => plot_07-ModelObject.py} (99%) diff --git a/tutorials/plot_04-PeriodicFitting.py b/tutorials/plot_04-PeriodicFitting.py index 3907ea26..94205d1c 100644 --- a/tutorials/plot_04-PeriodicFitting.py +++ b/tutorials/plot_04-PeriodicFitting.py @@ -1,5 +1,5 @@ """ -XX: Periodic Component Fitting +04: Periodic Component Fitting =============================== Choosing and using different modes for fitting the periodic component. diff --git a/tutorials/plot_06-Metrics.py b/tutorials/plot_06-Metrics.py index 8cb38309..13eb3d91 100644 --- a/tutorials/plot_06-Metrics.py +++ b/tutorials/plot_06-Metrics.py @@ -1,5 +1,5 @@ """ -XX: Metrics & Model Evaluation +06: Metrics & Model Evaluation ============================== An overview of metrics & model evaluation to examine model fit quality. diff --git a/tutorials/plot_04-ModelObject.py b/tutorials/plot_07-ModelObject.py similarity index 99% rename from tutorials/plot_04-ModelObject.py rename to tutorials/plot_07-ModelObject.py index 27ca6e9d..6fac465b 100644 --- a/tutorials/plot_04-ModelObject.py +++ b/tutorials/plot_07-ModelObject.py @@ -1,5 +1,5 @@ """ -XX: Exploring the model object +07: Exploring the model object ============================== Further exploring the SpectralModel object, including algorithm settings and available methods. diff --git a/tutorials/plot_08-GroupFits.py b/tutorials/plot_08-GroupFits.py index 79fa7132..079cc8b8 100644 --- a/tutorials/plot_08-GroupFits.py +++ b/tutorials/plot_08-GroupFits.py @@ -1,5 +1,5 @@ """ -06: Fitting group of spectra +08: Fitting group of spectra ============================ Using the group model object to run fit models across multiple power spectra. diff --git a/tutorials/plot_09-TimeModels.py b/tutorials/plot_09-TimeModels.py index 4a087272..21707168 100644 --- a/tutorials/plot_09-TimeModels.py +++ b/tutorials/plot_09-TimeModels.py @@ -1,5 +1,5 @@ """ -07: Fitting Models over Time +09: Fitting Models over Time ============================ Use extensions of the model object to fit power spectra across time. diff --git a/tutorials/plot_10-TroubleShooting.py b/tutorials/plot_10-TroubleShooting.py index aa45b7d2..c3f04d33 100644 --- a/tutorials/plot_10-TroubleShooting.py +++ b/tutorials/plot_10-TroubleShooting.py @@ -1,5 +1,5 @@ """ -08: Tuning & Troubleshooting +10: Tuning & Troubleshooting ============================ Tips & tricks for choosing algorithm settings, tuning fits, and troubleshooting. diff --git a/tutorials/plot_11-FurtherAnalysis.py b/tutorials/plot_11-FurtherAnalysis.py index 179dfa82..3060b4c7 100644 --- a/tutorials/plot_11-FurtherAnalysis.py +++ b/tutorials/plot_11-FurtherAnalysis.py @@ -1,5 +1,5 @@ """ -09: Further Analysis +11: Further Analysis ==================== Analyze results from fitting power spectrum models. diff --git a/tutorials/plot_12-Reporting.py b/tutorials/plot_12-Reporting.py index e901a058..0071777c 100644 --- a/tutorials/plot_12-Reporting.py +++ b/tutorials/plot_12-Reporting.py @@ -1,5 +1,5 @@ """ -10: Reporting & Referencing +12: Reporting & Referencing =========================== This section covers how to access reporting info and reference use of the module. From e2bf77910af1998543b9cae5071e7d02c903e10f Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Thu, 30 Oct 2025 01:16:45 +0000 Subject: [PATCH 5/9] add check_metrics --- specparam/metrics/definitions.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/specparam/metrics/definitions.py b/specparam/metrics/definitions.py index 1125864b..321a69c4 100644 --- a/specparam/metrics/definitions.py +++ b/specparam/metrics/definitions.py @@ -71,3 +71,11 @@ 'gof_adjrsquared' : gof_adjrsquared, } + + +def check_metrics(): + """Check the set of available metrics.""" + + print('Available metrics:') + for metric in METRICS.values(): + print(' {:8s} {:12s} : {:s}'.format(metric.category, metric.measure, metric.description)) From e1126652d226b859f15fd1c73e2c734b34bae4ea Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Thu, 30 Oct 2025 01:16:59 +0000 Subject: [PATCH 6/9] update metrics tutorial --- tutorials/plot_06-Metrics.py | 163 +++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 15 deletions(-) diff --git a/tutorials/plot_06-Metrics.py b/tutorials/plot_06-Metrics.py index 13eb3d91..e937f6cc 100644 --- a/tutorials/plot_06-Metrics.py +++ b/tutorials/plot_06-Metrics.py @@ -5,32 +5,165 @@ An overview of metrics & model evaluation to examine model fit quality. """ +################################################################################################### + +# Import the model object +from specparam import SpectralModel + +# Import function to check available list of metrics +from specparam.metrics.definitions import check_metrics + +# Import a utility to download and load example data +from specparam.utils.download import load_example_data + ################################################################################################### # Model Metrics # ------------- # # In this tutorial, we will explore model metrics. # -# The `specparam` module uses the term `metric` to refer to a measure that is computed that -# reflects something about the spectral model (but that is not computed as part of the model fit). +# The `specparam` module uses the term `metric` to refer to a measure that reflect something +# about the spectral model (but that is not computed as part of the model fit). # +# Generally, these metrics are used to evaluate how well the model fits the data +# and thus to assess the quality of the model fits. +# +# The module comes with various available metrics. To see the list of available metrics, +# we can use the :func:`~specparam.metrics.definitions.check_metrics` function. # +################################################################################################### + +# Check the list of available metrics +check_metrics() + ################################################################################################### # +# As we can see above, metrics are organized into categories, including 'error' and 'gof' +# (goodness of fit). Within each category there are different specific measures. # +# Broadly, error measures compute an error measure reflecting the difference between the +# full model fit and the original data. Goodness-of-fit measures compute the correspondence +# between the model and data. # ################################################################################################### -# Interpreting Model Fit Quality Measures -# --------------------------------------- +# Specifying Metrics +# ~~~~~~~~~~~~~~~~~~ +# +# Which metrics are computed depends on how the model object is initialized. When initializing +# a model object, which metrics to use can be specified using the `metrics` argument. +# When fitting a model, these metrics will then be automatically calculated after the +# model fitting and stored in the model object. +# + +################################################################################################## + +# Download example data files needed for this example +freqs = load_example_data('freqs.npy', folder='data') +spectrum = load_example_data('spectrum.npy', folder='data') + +################################################################################################### + +# Define a set of metrics to use +metrics1 = ['error_mae', 'gof_rsquared'] + +# Initialize model with metric specification & fit model +fm1 = SpectralModel(metrics=metrics1) +fm1.report(freqs, spectrum) + +################################################################################################### +# +# After model fitting, values of the computed metrics can be accessed with the +# :func:`~specparam.SpectralModel.results.get_metrics` method. +# + +################################################################################################### + +print('Error: ', fm1.get_metrics('error', 'mae')) +print('GOF: ', fm1.get_metrics('gof', 'squared')) + +################################################################################################### +# +# All the metric results are stored with a Metrics sub-component of the model results, from +# which you can also directly access all the metric results. +# + +################################################################################################### + +# Check the full set of metric results +print(fm1.results.metrics.results) + +################################################################################################### +# Default Metrics +# ~~~~~~~~~~~~~~~ +# +# You might notice that when specifying the metrics above, we specified metrics that have been +# available during model fitting previously, even when we did not explicitly specify them. +# +# The two specified metrics above are actually the default metrics, which are selected +# if no explicit metrics definition is given, as we've seen in previous examples. +# + +################################################################################################### +# Changing Metrics +# ~~~~~~~~~~~~~~~~ # -# After model fitting, some goodness of fit metrics are calculated to assist with assessing -# the quality of the model fits. It calculates both the model fit error, as the mean absolute -# error (MAE) between the full model fit (``modeled_spectrum_``) and the original power spectrum, -# as well as the R-squared correspondence between the original spectrum and the full model. +# We can use explicit metric specification to select different metrics to compute, as in the +# next example. # +################################################################################################### + +# Define a new set of metrics to use +metrics2 = ['error_mse', 'gof_adjrsquared'] + +# Initialize model with metric specification & fit model +fm2 = SpectralModel(metrics=metrics2) +fm2.report(freqs, spectrum) + +################################################################################################### +# Adding Additional Metrics +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# We are also not limited to a specific number of metrics. In the following example, we can +# specify a whole selection of different metrics. +# + +################################################################################################### + +# Define a new set of metrics to use +metrics3 = ['error_mae', 'error_mse', 'gof_rsquared', 'gof_adjrsquared'] + +# Initialize model with metric specification & fit model +fm3 = SpectralModel(metrics=metrics3) +fm3.report(freqs, spectrum) + +################################################################################################### +# +# Note that when using get_metrics, you specify the category and measure names. +# +# To return all available metrics within a specific category, leave the measure specification blank. +# + +################################################################################################### + +print(fm3.get_metrics('error')) +print(fm3.get_metrics('error', 'mse')) + +################################################################################################### +# +# As before you can also check the full set of metric results from the object results. +# + +################################################################################################### + +print(fm3.results.metrics.results) + +################################################################################################### +# Interpreting Model Fit Quality Measures +# --------------------------------------- +# # These scores can be used to assess how the model is performing. However interpreting these # measures requires a bit of nuance. Model fitting is NOT optimized to minimize fit error / # maximize r-squared at all costs. To do so typically results in fitting a large number of peaks, @@ -52,11 +185,11 @@ # for a given modality / dataset / application. # - -################################################################################################### - - -################################################################################################### - - ################################################################################################### +# Defining Custom Metrics +# ----------------------- +# +# In this tutorial, we have explored specifying and using metrics by selecting from measures +# that are defined and available within the module. You can also define custom metrics if +# that is useful for your use case - see an example of this in the Examples. +# From 0cd3cd59010a38fd7b7542cc2159ba9f4618a0a9 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Thu, 30 Oct 2025 01:53:24 +0000 Subject: [PATCH 7/9] update pe fitting --- tutorials/plot_04-PeriodicFitting.py | 124 ++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 13 deletions(-) diff --git a/tutorials/plot_04-PeriodicFitting.py b/tutorials/plot_04-PeriodicFitting.py index 94205d1c..79220d2a 100644 --- a/tutorials/plot_04-PeriodicFitting.py +++ b/tutorials/plot_04-PeriodicFitting.py @@ -10,27 +10,76 @@ # Import the model object from specparam import SpectralModel +# Import function to check available list of modes +from specparam.modes.definitions import check_modes + # Import a utility to download and load example data from specparam.utils.download import load_example_data +################################################################################################### +# Component Fit Modes +# ------------------- +# +# So far, we have initialized spectral fitting without explicitly specifying what model we want +# to fit the the data. By doing so, we have been using the default model definition. +# +# However, we can also control which model forms we fit to the data, separately for the +# periodic and aperiodic components. This is done by explicitly specifying Fit Modes for +# each model component. +# +# In this part of the tutorial, we will explore how this works for the periodic component. +# + ################################################################################################### # Periodic Fitting Approaches # --------------------------- # -# Words, words, words +# As we've already seen, to fit putatively periodic activity - operationalized as regions +# of power over above the aperiodic component - the model fits 'peaks'. +# +# However, in order to actually do this, we need to specify a mathematical definition of +# how to describe these peaks. Specifying this fit function is what is meant by +# choosing the periodic mode. +# +# To see the available periodic fit modes, we can use the +# :func:`~specparam.modes.definitions.check_modes` function. +# + +################################################################################################### + +# Check the list of periodic modes +check_modes('periodic') + +################################################################################################### +# Gaussian Periodic Mode +# ~~~~~~~~~~~~~~~~~~~~~~ +# +# We will start with choosing the Gaussian fit mode. # ################################################################################################### +# Download example data files needed for this example +freqs = load_example_data('freqs.npy', folder='data') +spectrum = load_example_data('spectrum.npy', folder='data') +################################################################################################### +# Initialize a model object, explicitly specifying periodic fit to 'gaussian' +fm1 = SpectralModel(periodic_mode='gaussian') + +# Fit the model +fm1.report(freqs, spectrum) ################################################################################################### # Mathematical Description of the Periodic Component # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# To fit this periodic activity - the regions of power over above the aperiodic component, -# or 'peaks' - the model uses Gaussians. As we've seen, there can be multiple peaks in the model. +# You might notice that the above model looks the same as what we have fit previously. +# The Gaussian periodic mode is the default periodic mode. +# +# Now that we have explicitly specified the Gaussian periodic fit mode, we can look into +# how the model is actually fit. # # Each Gaussian, :math:`n`, referred to as :math:`G(F)_n`, is of the form: # @@ -45,22 +94,43 @@ # - :math:`F` is the array of frequency values # +################################################################################################### +# Check the fit gaussian parameters +fm1.results.get_params('periodic', version='fit') ################################################################################################### -# Notes on Interpreting Peak Parameters -# ------------------------------------- +# Fit vs. Converted Parameters +# ---------------------------- +# +# You might notice in the above, where we printed out the periodic parameters, that in doing +# so we specified explicitly to get the 'fit' version of the parameters, and that these +# parameters are actually a bit different than the peak parameters reported in the report above. +# +# This is because the model manages two version of each component parameters: +# - `fit`: which reflect the original fit parameters, that define the model +# - `converted`: which reflect parameters after any relevant conversions # -# Peak parameters are labeled as: +# The reason we may want to apply to conversions to the parameters is that the fit versions, +# while defining the model, may not reflect what we actually want to analyze as outputs. +# + +################################################################################################### + +# Check the fit gaussian parameters +fm1.results.get_params('periodic', version='converted') + +################################################################################################### +# Converted Peak Parameters +# ~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# The converted peak parameters are labeled as: # # - CF: center frequency of the extracted peak # - PW: power of the peak, over and above the aperiodic component # - BW: bandwidth of the extracted peak # -# Note that the peak parameters that are returned are not exactly the same as the -# parameters of the Gaussians used internally to fit the peaks. -# -# Specifically: +# The conversions that are applied to get these values are that: # # - CF is the exact same as mean parameter of the Gaussian # - PW is the height of the model fit above the aperiodic component [1], @@ -77,17 +147,45 @@ # ################################################################################################### +# Specifying a Different Fit Mode: Skewed Gaussian +# ------------------------------------------------ +# +# As we saw above with `check_modes` there are also other periodic fit modes we can choose. # -# The underlying gaussian parameters are also available from the model object, -# in the ``gaussian_params_`` attribute. +# Next up, let's try the `skewed_gaussian` mode. # +################################################################################################### + +# Initialize a model object, explicitly specifying periodic fit to 'gaussian' +fm2 = SpectralModel(periodic_mode='skewed_gaussian') + +# Fit the model +fm2.report(freqs, spectrum) ################################################################################################### +# +# In the above, we can see that the peaks are fit a bit differently. +# +# Note that the resulting parameters are also different. +# +################################################################################################### +# Specifying a Different Fit Mode: Cauchy +# --------------------------------------- +# +# Finally, we can try the remaining periodic mode, the cauchy distribution! +# ################################################################################################### +# Initialize a model object, explicitly specifying periodic fit to 'gaussian' +fm3 = SpectralModel(periodic_mode='cauchy') +# Fit the model +fm3.report(freqs, spectrum) -################################################################################################### \ No newline at end of file +################################################################################################### +# +# That covers periodic mode selection! +# From c746cc47d2ed7459bb9c4c8d652d7afa9c75df30 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Thu, 30 Oct 2025 02:00:56 +0000 Subject: [PATCH 8/9] interim update: ap --- tutorials/plot_05-AperiodicFitting.py | 80 +++++++++++++++------------ 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/tutorials/plot_05-AperiodicFitting.py b/tutorials/plot_05-AperiodicFitting.py index c8a62fc8..d1ed1c0f 100644 --- a/tutorials/plot_05-AperiodicFitting.py +++ b/tutorials/plot_05-AperiodicFitting.py @@ -10,44 +10,47 @@ # Import the model object from specparam import SpectralModel +# Import function to check available list of modes +from specparam.modes.definitions import check_modes + # Import a utility to download and load example data from specparam.utils.download import load_example_data ################################################################################################### -# Aperiodic Fit Modes +# Component Fit Modes # ------------------- # -# There are currently two approaches for fitting the aperiodic component: -# -# - Fitting with just an offset and a exponent, equivalent to a linear fit in log-log space +# Just like for the periodic mode, the aperiodic component has different fit modes that +# can be applied to the data. # -# - `aperiodic_mode` = 'fixed' -# - Including a 'knee' parameter, reflecting a fit with a bend, in log-log space + +################################################################################################### + +# Check the available aperiodic fit modes +check_modes('aperiodic') + +################################################################################################### +# Aperiodic Fit Mode: fixed +# ------------------------- # -# - `aperiodic_mode` = 'knee' +# The 'fixed' aperiodic mode fits the aperiodic component with an offset and a exponent, # # Fitting in the 'fixed' mode assumes a single 1/f like characteristic to the aperiodic # component, meaning it looks linear across all frequencies in log-log space. # -# Though this assumption is true across *some* frequency ranges in neural data, it generally -# does not hold up across broad frequency ranges. If fitting is done in the 'fixed' mode, -# but the assumption of a single 1/f is violated, then fitting will go wrong. -# -# Broad frequency ranges (typically ranges greater than ~40 Hz range) typically do not -# have a single 1/f, as assumed by 'fixed' mode, as they typically exhibit a 'bend' in -# the aperiodic component. This indicates that there is not a single 1/f property across -# all frequencies, but rather a 'bend' in the aperiodic component. For these cases, fitting -# should be done using an extra parameter to capture this, using the 'knee' mode. +# This is the default aperiodic fit mode, and the one we have been using in the previous examples. # +################################################################################################### - - +fm1 = SpectralModel(aperiodic_mode='fixed') ################################################################################################### # Relating Exponents to Power Spectrum Slope # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # +# The 'fixed' mode is equivalent to a linear fit in log-log space +# # Another way to measure 1/f properties in neural power spectra is to measure the slope # of the spectrum in log-log spacing, fitting a linear equation as: # @@ -72,8 +75,31 @@ # +################################################################################################### +# Aperiodic Fit Mode: knee +# ------------------------ +# +# Another available aperiodic fit mode is the 'knee' mode, which includes a 'knee' parameter, +# reflecting a fit with a bend, in log-log space. +# +# Adding a knee is done because +# +# +# Though this assumption is true across *some* frequency ranges in neural data, it generally +# does not hold up across broad frequency ranges. If fitting is done in the 'fixed' mode, +# but the assumption of a single 1/f is violated, then fitting will go wrong. +# +# Broad frequency ranges (typically ranges greater than ~40 Hz range) typically do not +# have a single 1/f, as assumed by 'fixed' mode, as they typically exhibit a 'bend' in +# the aperiodic component. This indicates that there is not a single 1/f property across +# all frequencies, but rather a 'bend' in the aperiodic component. For these cases, fitting +# should be done using an extra parameter to capture this, using the 'knee' mode. +# +################################################################################################### + +fm2 = SpectralModel(aperiodic_mode='knee') ################################################################################################### # Mathematical Description of the Aperiodic Component @@ -112,24 +138,6 @@ # AP(F) = 10^b * \frac{1}{(k + F^\chi)} # - - - - - - - - - - - - -################################################################################################### -# -# -# -# - ################################################################################################### # Fitting with an Aperiodic 'Knee' # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f917a142f902453565e6b801e326e7e7faef46d0 Mon Sep 17 00:00:00 2001 From: Tom Donoghue Date: Thu, 30 Oct 2025 10:33:39 +0000 Subject: [PATCH 9/9] sweep of updates --- tutorials/plot_01-ModelDescription.py | 13 ++++-- tutorials/plot_03-Algorithm.py | 12 ++--- tutorials/plot_05-AperiodicFitting.py | 26 +++++------ tutorials/plot_07-ModelObject.py | 67 +++++++++++++-------------- tutorials/plot_11-FurtherAnalysis.py | 8 ++-- tutorials/plot_12-Reporting.py | 7 ++- 6 files changed, 69 insertions(+), 64 deletions(-) diff --git a/tutorials/plot_01-ModelDescription.py b/tutorials/plot_01-ModelDescription.py index e8dcb16c..a7bee300 100644 --- a/tutorials/plot_01-ModelDescription.py +++ b/tutorials/plot_01-ModelDescription.py @@ -290,14 +290,19 @@ # # So far, we have explored how neural power spectra, :math:`NPS`, across a set of frequencies # :math:`F` can be modeled as a combination of an aperiodic component, :math:`L`, and the -# periodic component, which is comprised of `N` peaks, where each :math:`G_n` is a Gaussian. +# periodic component (P), which is comprised of a group of `N` peaks. # -# To summarize, the full model is: +# To summarize, the full model, in abstract terms, is: # # .. math:: -# NPS(F) = L(F) + G(F)_n +# NPS(F) = L(F) + P(F)_n # -# where: +# In further tutorials we will dig into the details of choosing specific fit functions +# to instantiate this model. For now, using the defaults as above, we have +# been fitting a model that uses fits the the aperiodic component as a Lorentzian, +# and the periodic component as Gaussians. +# +# Using these fit functions, the model has this form: # # .. math:: # L(F) = b - \log(k + F^\chi) \quad \quad G(F)_n = a * exp (\frac{- (F - c)^2}{2 * w^2}) diff --git a/tutorials/plot_03-Algorithm.py b/tutorials/plot_03-Algorithm.py index 2517b479..a15ec41e 100644 --- a/tutorials/plot_03-Algorithm.py +++ b/tutorials/plot_03-Algorithm.py @@ -273,27 +273,27 @@ # # Stored model components: # -# - Aperiodic Component: ``_ap_fit`` +# - Aperiodic Component (``SpectralModel.results.model.get_component('aperiodic')``) # # - This is the aperiodic-only fit of the data. # - It is computed by generating a reconstruction of the measured aperiodic parameters # -# - Periodic Component: ``_peak_fit`` +# - Periodic Component: (``SpectralModel.results.model.get_component('peak')``) # # - This is the periodic-only (or peak) fit of the data. # - It is computed by generating a reconstruction of the measured periodic (peak) parameters # # Stored data attributes: # -# - Flattened Spectrum: ``_spectrum_flat`` +# - Flattened Spectrum: (``SpectralModel.get_data('aperiodic')``) # # - The original data, with the aperiodic component removed -# - This is computed as ``power_spectrum`` - ``_ap_fit`` +# - This is computed as the power_spectrum minus the model aperiodic fit # -# - Peak Removed Spectrum: ``_spectrum_peak_rm`` +# - Peak Removed Spectrum: (``SpectralModel.get_data('aperiodic')``) # # - The original data, with the periodic component (peaks) removed -# - This is computed as ``power_spectrum`` - ``_peak_fit`` +# - This is computed as the power_spectrum minus the model peak fit # ################################################################################################### diff --git a/tutorials/plot_05-AperiodicFitting.py b/tutorials/plot_05-AperiodicFitting.py index d1ed1c0f..3f67fbdd 100644 --- a/tutorials/plot_05-AperiodicFitting.py +++ b/tutorials/plot_05-AperiodicFitting.py @@ -33,12 +33,17 @@ # Aperiodic Fit Mode: fixed # ------------------------- # -# The 'fixed' aperiodic mode fits the aperiodic component with an offset and a exponent, -# # Fitting in the 'fixed' mode assumes a single 1/f like characteristic to the aperiodic # component, meaning it looks linear across all frequencies in log-log space. # -# This is the default aperiodic fit mode, and the one we have been using in the previous examples. +# The 'fixed' aperiodic mode fits the aperiodic component with an offset and a exponent, +# using the following definition: +# +# .. math:: +# L(F) = b - \log(F^\chi) +# +# Note that this is the default aperiodic fit mode, +# and the one we have been using in the previous examples. # ################################################################################################### @@ -74,7 +79,6 @@ # \chi = -a # - ################################################################################################### # Aperiodic Fit Mode: knee # ------------------------ @@ -82,11 +86,8 @@ # Another available aperiodic fit mode is the 'knee' mode, which includes a 'knee' parameter, # reflecting a fit with a bend, in log-log space. # -# Adding a knee is done because -# - -# -# Though this assumption is true across *some* frequency ranges in neural data, it generally +# Adding a knee is done because also the although the assumption of a linear log-log property +# is typically true across *some* frequency ranges in neural data, it generally # does not hold up across broad frequency ranges. If fitting is done in the 'fixed' mode, # but the assumption of a single 1/f is violated, then fitting will go wrong. # @@ -99,13 +100,14 @@ ################################################################################################### +# Initialize a new spectral model with the knee aperiodic mode fm2 = SpectralModel(aperiodic_mode='knee') ################################################################################################### # Mathematical Description of the Aperiodic Component # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # -# To fit the aperiodic component, we will use the function :math:`L`: +# To fit the aperiodic component with a knee, we will use the following function :math:`L`: # # .. math:: # L(F) = b - \log(k + F^\chi) @@ -121,10 +123,6 @@ # - :math:`\chi` is the 'exponent' of the aperiodic fit # - :math:`F` is the array of frequency values # -# Note that fitting the knee parameter is optional. If used, the knee parameter defines a -# 'bend' in the aperiodic `1/f` like component of the data. If not used, the 'knee' -# parameter is set to zero. -# # This function form is technically described as a Lorentzian function. We use the option # of adding a knee parameter, since even though neural data is often discussed in terms # of having `1/f` activity, there is often not a single `1/f` characteristic, especially diff --git a/tutorials/plot_07-ModelObject.py b/tutorials/plot_07-ModelObject.py index 6fac465b..ed1dcac8 100644 --- a/tutorials/plot_07-ModelObject.py +++ b/tutorials/plot_07-ModelObject.py @@ -102,17 +102,6 @@ # used and the peak search will halt when a candidate peak fails to pass either the absolute, # or relative threshold. # -# Aperiodic Mode -# ~~~~~~~~~~~~~~ -# -# **aperiodic_mode (string)** default='fixed' -# -# The fitting approach to use for the aperiodic component. -# -# Options: -# - 'fixed' : fits without a knee parameter (with the knee parameter 'fixed' at 0) -# - 'knee' : fits the full exponential equation, including the 'knee' parameter -# # Verbosity # ~~~~~~~~~ # @@ -157,10 +146,10 @@ # - ``freq_range``: the frequency range of the data # - ``freq_res``: the frequency resolution of the data # -# During the fit procedure, interim (hidden) data variables are also created and used. +# Note that these are all stored in a data object that is stored as a component of the +# overall model object (``SpectralModel.data``). # -# There is also an indicator attribute, ``has_data`` which indicates -# if the current object has data loaded. +# During the fit procedure, interim (hidden) data variables are also created and used. # ################################################################################################### @@ -177,17 +166,23 @@ ################################################################################################### -# Check if the object has data loaded -print('Has data loaded: ', fm.data.has_data) - -################################################################################################### - # Check out the data attributes in the object print('Frequency Range: \t', fm.data.freq_range) print('Frequency Resolution: \t', fm.data.freq_res) print('Frequency Values: \t', fm.data.freqs[0:5]) print('Power Values: \t\t', fm.data.power_spectrum[0:5]) +################################################################################################### +# +# There is also an indicator attribute, ``has_data`` which indicates +# if the current object has data loaded. +# + +################################################################################################### + +# Check if the object has data loaded +print('Has data loaded: ', fm.data.has_data) + ################################################################################################### # # Now that we have picked our settings, and added the data, let's fit a power spectrum model. @@ -207,29 +202,22 @@ # Recall that by convention, any attributes that contain model results are # indicated by a trailing underscore. # -# The model results stored by the object are: +# The model parameter results stored by the object include: # -# - ``aperiodic_params_``: a list of aperiodic parameters, stored as [Offset, (Knee), Exponent] -# - ``peak_params_``: all periodic parameters, where each row is a peak, as [CF, PW, BW] -# - ``r_squared_``: the r-squared of the model, as compared to the original data -# - ``error_``: the error of the model, as compared to the original data +# - ``aperiodic_params``: a list of aperiodic parameters, stored as [Offset, (Knee), Exponent] +# - ``peak_params``: all periodic parameters, where each row is a peak, as [CF, PW, BW] # -# Other attributes which store outputs from the model are: +# The model object also computes and stores metrics to assess the model: # -# - ``modeled_spectrum_``: the full model reconstruction -# - ``n_peaks_``: a helper attribute which indicates how many peaks were fit in the model +# - ``gof``: goodness of fit measures of the model, as compared to the original data +# - ``error``: the error measures of the model, as compared to the original data # -# The :class:`~specparam.SpectralModel` object also has an indicator attribute, ``has_model`` -# which indicates if the current object has model results available. +# Note that these are all stored in a results object that is stored as a component of the +# overall model object (``SpectralModel.results``). # ################################################################################################### -# Check if the object has model results -print('Has model results: ', fm.results.has_model) - -################################################################################################### - # Print out model fit results parameters print('aperiodic params: \t', fm.results.params.aperiodic.params) print('peak params: \t', fm.results.params.periodic.params) @@ -238,6 +226,17 @@ print('fit error: \t', fm.results.metrics.results['error_mae']) print('r-squared: \t', fm.results.metrics.results['gof_rsquared']) +################################################################################################### +# +# The :class:`~specparam.SpectralModel` object also has an indicator attribute, ``has_model`` +# which indicates if the current object has model results available. +# + +################################################################################################### + +# Check if the object has model results +print('Has model results: ', fm.results.has_model) + ################################################################################################### # 4) Methods # ^^^^^^^^^^ diff --git a/tutorials/plot_11-FurtherAnalysis.py b/tutorials/plot_11-FurtherAnalysis.py index 3060b4c7..febf5c6b 100644 --- a/tutorials/plot_11-FurtherAnalysis.py +++ b/tutorials/plot_11-FurtherAnalysis.py @@ -261,12 +261,10 @@ # page. # + ################################################################################################### -# Conclusion -# ---------- # -# This is the end of the main tutorial materials! +# That concludes this brief discussion of further analyses. # -# If you are having any troubles, please submit an issue on Github -# `here `_. +# See the Examples page for more overviews of analyses ideas and utilities. # diff --git a/tutorials/plot_12-Reporting.py b/tutorials/plot_12-Reporting.py index 0071777c..19871925 100644 --- a/tutorials/plot_12-Reporting.py +++ b/tutorials/plot_12-Reporting.py @@ -162,6 +162,11 @@ methods_report_text(fg) ################################################################################################### +# Conclusion +# ---------- # -# That concludes the example of using the helper utilities for generating methods reports! +# This is the end of the main tutorial materials! +# +# If you are having any troubles, please submit an issue on Github +# `here `_. #