.. _user_guide_extending:
Extending pepbench with Your Own Algorithm
==========================================
pepbench is designed to be **extensible**: you can add new PEP extraction
algorithms and still reuse the existing pipelines and evaluation
infrastructure.
This guide outlines the main steps:
1. Implement a new algorithm class in the appropriate module.
2. Document it with a clear docstring and literature reference.
3. (Optionally) expose it in the public API.
4. Use it in :class:`PepExtractionPipeline` and
:class:`PepEvaluationChallenge`.
Where to put new algorithms
---------------------------
The algorithm modules follow a structure similar to the
`mobgap `_ toolbox: base classes are in
“public” modules, concrete algorithms live in dedicated files and are
re-exported via ``__init__.py``.
pepbench has submodules such as:
* ``pepbench.algorithms.ecg`` – Q-peak algorithms
* ``pepbench.algorithms.icg`` – B- and C-point algorithms
* ``pepbench.algorithms.heartbeat_segmentation``
* ``pepbench.algorithms.outlier_correction``
Choose the module corresponding to your algorithm’s task. For example, a
new B-point strategy would go into ``pepbench/algorithms/icg/``.
Base classes and interface
--------------------------
Algorithms usually subclass *biopsykit* / tpcp-style base classes, e.g.:
* :class:`biopsykit.signals.ecg.BaseEcgExtraction`
* :class:`biopsykit.signals.icg.BaseBPointExtraction`
* :class:`biopsykit.signals.icg.BaseCPointExtraction`
The crucial requirements are:
* implement an :meth:`extract` method with signature compatible with the
base class (e.g., ``extract(ecg, heartbeats, sampling_rate_hz)`` for
Q-peak methods) and
* store results in a ``points_`` or similar attribute, as the existing
algorithms do.
A minimal example (Q-peak)
--------------------------
.. code-block:: python
# pepbench/algorithms/ecg/_my_q_peak_algo.py
from biopsykit.signals.ecg import BaseEcgExtraction
import pandas as pd
class QPeakExtractionMyMethod(BaseEcgExtraction):
"""Q-peak extraction algorithm based on .
This algorithm implements the Q-peak detection method described by
, adapted to the pepbench / tpcp interface.
Parameters
----------
some_parameter : float
Method-specific parameter controlling ...
handle_missing_events : {"warn", "raise", "ignore"}, optional
How to handle missing events in the input dataframes.
"""
def __init__(self, some_parameter=0.1, handle_missing_events="warn"):
self.some_parameter = some_parameter
self.handle_missing_events = handle_missing_events
def extract(self, *, ecg, heartbeats, sampling_rate_hz):
# Implement your detection here, using `ecg` and `heartbeats`
# Return self and populate `self.points_` similar to existing algorithms
q_points = self._detect_q_points(ecg, heartbeats, sampling_rate_hz)
self.points_ = pd.DataFrame({"q_peak": q_points}, index=heartbeats.index)
return self
def _detect_q_points(self, ecg, heartbeats, sampling_rate_hz):
# Your algorithm implementation here
...
Re-export the class in ``pepbench/algorithms/ecg/__init__.py`` so users
can import it as:
.. code-block:: python
from pepbench.algorithms.ecg import QPeakExtractionMyMethod
Docstring and references
------------------------
For scientific algorithms, it is essential to include:
* a short description of the method,
* the citation of the original paper (Journal, year, DOI), and
* any assumptions (e.g., sampling rate, filtering).
The existing algorithm docstrings (e.g.
:class:`QPeakExtractionVanLien2013`, :class:`BPointExtractionStern1985`)
are good examples to follow.
Integrating your algorithm into pipelines
-----------------------------------------
Once the class is implemented and importable, you can use it in
:class:`PepExtractionPipeline` just like the built-in algorithms:
.. code-block:: python
from pepbench.pipelines import PepExtractionPipeline
from pepbench.algorithms.heartbeat_segmentation import HeartbeatSegmentationNeurokit
from pepbench.algorithms.ecg import QPeakExtractionMyMethod
from pepbench.algorithms.icg import BPointExtractionLozano2007LinearRegression
pipeline = PepExtractionPipeline(
heartbeat_segmentation_algo=HeartbeatSegmentationNeurokit(),
q_peak_algo=QPeakExtractionMyMethod(some_parameter=0.2),
b_point_algo=BPointExtractionLozano2007LinearRegression(),
)
dp = next(iter(ds))
pipeline = pipeline.safe_run(dp)
pep_df = pipeline.pep_results_
Using the evaluation framework
------------------------------
To benchmark your new algorithm against existing ones, simply plug your
pipeline into :class:`PepEvaluationChallenge`:
.. code-block:: python
from pepbench.evaluation import PepEvaluationChallenge, score_pep_evaluation
challenge = PepEvaluationChallenge(
dataset=ds,
scoring=score_pep_evaluation,
)
challenge = challenge.run(pipeline).results_as_df()
print(challenge.results_agg_mean_std_)
This reproduces the **systematic benchmarking** idea of the PEPbench
paper, now including your custom algorithm.
Testing and quality checks
--------------------------
Following best practices from API usability and developer-tool
documentation, new algorithms should be accompanied by:
* unit tests verifying that ``extract`` runs and populates result
attributes,
* basic sanity checks on PEP distributions (no massive negative values,
reasonable ranges),
* clear docstrings and examples.
You can mirror the approach from the mobgap `Developer Guide` for
testing new algorithms, adapting tpcp’s
``TestAlgorithmMixin`` pattern to your needs.