spikecurate
author: steeve laquitaine - laquitainesteeve@gmail.com
Curate sorted single-unit quality from SpikeInterface extractors, using a fractional-logistic classifier trained on SpikeInterface quality metrics.
Given a recording, a ground-truth sorting, a sorter's output, the sorter's
own single-unit calls, and expert good/bad labels for a subset of those
units, spikecurate engineers quality-metric features, trains a classifier
of accurately- vs. poorly-sorted single units, and reports its
cross-validated precision/recall.
Install
pip install -e .
Documentation
Full API reference (built with Sphinx from the docstrings in src/spikecurate/):
https://steevelaquitaine.github.io/spikecurate/
Rebuilds automatically on every push to master
(.github/workflows/docs.yml). To build it locally:
pip install -e .[docs]
sphinx-build -b html docs docs/_build/html
Demo notebook
demo/demo_03.ipynb walks through FractionalLogisticClassifier's API -
train, crossval_evaluate, predict, score - using the real,
already-engineered feature dataset checked into this repo at
dataset/single_unit_quality_dataset.csv. No SpikeInterface extractors
needed, just pandas + spikecurate:
pip install -e .
python -m ipykernel install --user --name spikecurate --display-name spikecurate
jupyter notebook demo/demo_03.ipynb
Usage
import spikecurate
result = spikecurate.run(
recording=recording, # spikeinterface RecordingExtractor
sorting_true=sorting_true, # spikeinterface ground-truth SortingExtractor
sorting=sorting, # spikeinterface SortingExtractor (e.g. Kilosort4)
we_save_path="waveforms/single_units",
single_unit_ids=single_unit_ids, # e.g. sorting.unit_ids[sorting.get_property("KSLabel") == "good"]
good_unit_ids=good_unit_ids, # subset of single_unit_ids, >80% agreement with ground truth
bad_unit_ids=bad_unit_ids, # remaining subset of single_unit_ids
predict_unit_ids=single_unit_ids[:10], # units to classify with the trained model; defaults to all
job_kwargs=dict(n_jobs=-1, progress_bar=True),
)
result["feature_correlations"] # pd.DataFrame: feature correlation matrix
result["results"]["metric_stats"] # median/std/95% CI precision & recall, cross-validated
result["model"] # FractionalLogisticClassifier, trained on the full dataset
result["predictions"] # DataFrame indexed by unit id: probability, predicted_label, predicted_quality
The classifier's own API
spikecurate.run is a convenience pipeline built on top of
FractionalLogisticClassifier, which has a scikit-learn-flavored API and is
usable standalone (e.g. to retrain/re-predict without redoing waveform
extraction, or to classify units engineered outside spikecurate.run):
from spikecurate.model import FractionalLogisticClassifier
model = FractionalLogisticClassifier(predictors) # predictors: result["data"]["predictors"]
model.crossval_evaluate(dataset) # cross-validated precision/recall (each fold trains its own fit)
model.train(dataset) # fit on the full labeled dataset; returns self
model.predict(features) # DataFrame: probability, predicted_label, predicted_quality
model.score(dataset) # precision/recall of the trained model against dataset's own labels
features passed to predict just needs unit id as its index and the
columns in model.predictors - it doesn't need a quality_label column
(that's the whole point: predicting labels for units you don't already
have labels for).
Other pipeline stages are also usable standalone:
from spikecurate.features import load_dataset
from spikecurate.plotting import plot_precision_recall
Testing
tests/test_pipeline.py: end-to-end smoke test ofspikecurate.run()against synthetic SpikeInterface data. Runs on every push/PR (.github/workflows/tests.yml).tests/test_classification.py: pins the classifier's numeric output (crossval_evaluate,train+score,predict) againstdataset/single_unit_quality_dataset.csv- the same real engineered datasetdemo_03.ipynbwalks through - so a future change to the model/crossval/predict code that silently changes results, not just one that crashes, gets caught. Needs no SpikeInterface extractors, so it's fast. Runs on every push tomaster(.github/workflows/regression.yml).
Citation
If you use this package, please consider citing:
Laquitaine, S., Imbeni, M., Tharayil, J., Isbister, J. B., & Reimann, M. W. (2024). Spike sorting biases and information loss in a detailed cortical model. bioRxiv. https://doi.org/10.1101/2024.12.04.626805
@article{laquitaine2024spikesorting,
title = {Spike sorting biases and information loss in a detailed cortical model},
author = {Laquitaine, Steeve and Imbeni, Milo and Tharayil, Joseph and Isbister, James B. and Reimann, Michael W.},
journal = {bioRxiv},
year = {2024},
doi = {10.1101/2024.12.04.626805},
url = {https://www.biorxiv.org/content/10.1101/2024.12.04.626805v1}
}
License
GNU General Public License v3.0 - see LICENSE.
Notes
- Requires a
principal_componentsextension on the WaveformExtractor (computed automatically byspikecurate.run) - the silhouette quality metric depends on it. good_unit_idsandbad_unit_idsmust partitionsingle_unit_idsexactly (every single unit gets exactly one label) -spikecurate.runwill raiseAssertionErrorotherwise.features.load_datasetalways returnsdatasetsorted by unit id (dataset.sort_index()).FractionalLogisticClassifier.crossval_evaluate's cross-validation splits train/test by row position (random.sample(range(n), n_train)), so for a givendatasetandseeds, results are reproducible only if row order is pinned - passing an unsorted dataset (e.g. one you built yourself, in whatever order the sorting extractor's unit ids happened to come in) will still run, but won't reproduce the same split as the same content sorted differently.
Metadata
Release files for spikecurate 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| spikecurate-0.1.0.tar.gz | 28.3 kB | Without provenance | Details for spikecurate-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| spikecurate-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for spikecurate-0.1.0-py3-none-any.whl |
Total release size: 54.9 kB
Release files / spikecurate-0.1.0.tar.gz
| Download URL | spikecurate-0.1.0.tar.gz |
|---|---|
| Size | 28.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
08c4a82809674f9600a33d9a770868ff8799b99052c2e2c46ab8384a3e5c862f
|
|
BLAKE2b-256 checksum How to use checksums |
ece6b3f5a67742087a89aa1af0679d64033a291e3156a1d266db287423192229
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.7
|
Release files / spikecurate-0.1.0-py3-none-any.whl
| Download URL | spikecurate-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5c3733b78d6659b11920cd90d26c1c325611db8738b9c7ec95e0ec42f190d4dd
|
|
BLAKE2b-256 checksum How to use checksums |
d9aabc9e22442f8ffeaf464a479db055c74f72a63aa8799484dfa4a5a54d25c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.7
|
Security for spikecurate 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.