biosenter - Sentence splitting for biomedical text
biosenter is a small spaCy sentence-boundary model plus markup-aware pre/post-processing, trained and evaluated specifically against PMC full text and PubMed abstracts with LLM-annotated sentence boundaries.
Why?
- Generic sentence splitters break constantly on biomedical text
- Full stops appear everywhere in biomedical text (
Fig. 1,et al.) and can easily fool a parser into splitting sentence in the wrong place - Other tools don't deal nicely with citations that hang at the ends of sentences
Install
pip install biosenter
A trained model ships with the package, so split_into_sentences works out
of the box with no extra configuration. It integrates directly with bioconverters
for extracting text from PMC JATS XML and PubMed baseline/update XML.
Usage
1. Direct spaCy usage
For plain, markup-free text (e.g. PubMed abstracts):
import spacy
nlp = spacy.load("biosenter")
doc = nlp("As shown in Fig. 1, expression increased. A second effect was seen in Fig. 2.")
for sent in doc.sents:
print(sent.text)
2. Formatting & citation-aware with bioconverters
Real PMC full text carries inline markup and citation markers that spaCy won't treat nicely. Combine functionality from the bioconverters package with the split_into_sentences function to keep formatting and citations in the right sentences:
from bioconverters import pmcxml2tagged
from biosenter import split_into_sentences
# pmcxml2tagged() yields (metadata, text) pairs with inline markup and
# citations preserved, e.g.:
# 'Recurrent <italic>C. difficile</italic> infection is common
# (<citation pmid="23079555">1</citation>).'
for meta, text in pmcxml2tagged('PMC1234567.xml'):
for start, end, sentence in split_into_sentences(text):
print(sentence)
Benchmarks
Sentence-boundary F1 against corpus/test/ -- 100 randomly-sampled PMC
articles that the model was neither trained nor checkpoint-selected on --
excluding the formatting/citation handling. The articles used to train and
evaluate with were annotated by Claude Sonnet and Opus.
| Model | corpus/test/ |
|---|---|
| spaCy rule-based sentencizer | F1 0.9107 (P 0.8701, R 0.9552) |
en_core_web_sm |
F1 0.9506 (P 0.9192, R 0.9843) |
scispacy en_core_sci_sm |
F1 0.9763 (P 0.9846, R 0.9681) |
| biosenter (bundled) | F1 0.9891 (P 0.9854, R 0.9928) |
Reproduce with scripts/evaluate_senter.py, which loads any of these by
name (they're all just installed spaCy packages):
pip install en_core_web_sm # or: python -m spacy download en_core_web_sm
python scripts/evaluate_senter.py --models rule en_core_web_sm biosenter/model \
--pmc_eval_dir corpus/test
scispacy's released models pin to an older spaCy than biosenter requires
(en_core_sci_sm 0.5.4 needs spacy<3.8) -- their own README recommends an
isolated environment for exactly this reason, so run it separately:
pip install scispacy
pip install https://s3-us-west-2.amazonaws.com/ai2-s2-scispacy/releases/v0.5.4/en_core_sci_sm-0.5.4.tar.gz
pip install --no-deps -e . # biosenter itself, for split_into_sentences -- skip its spacy>=3.8 pin here
python scripts/evaluate_senter.py --models en_core_sci_sm --pmc_eval_dir corpus/test
Retraining / evaluating
The bundled model, the corpus it was trained on, and the tooling to rebuild or extend either are all included:
corpus/train/(300),corpus/validation/(100) andcorpus/test/(100) -- LLM-annotated PMC articles used to train, tune and score the bundled model. Seecorpus/README.mdfor the dataset schema, the annotation conventions, and how it was built.scripts/fetch_pmc.py-- fetch more PMC Open Access articles (random or by PMCID), filtered to commercially-redistributable licenses by default.scripts/build_senter_corpus.py-- turn fetched XML into corpus records with boundaries bootstrapped from the current model, ready to correct.scripts/flag_boundaries.py-- screen a split for likely boundary mistakes (seecorpus/README.md) before/after correcting it.scripts/prepare_pmc_senter_corpus.py-- convertcorpus/{train,validation,test}into spaCy training data.scripts/train_senter.py-- train a new model.scripts/evaluate_senter.py-- score a model against the hand-labelled eval set.
python scripts/prepare_pmc_senter_corpus.py --corpus_dir corpus/train --out_path data/senter/pmc_train.spacy
python scripts/prepare_pmc_senter_corpus.py --corpus_dir corpus/validation --out_path data/senter/pmc_val.spacy
python scripts/train_senter.py --data_dir data/senter --run_name my_run --seed 0
python scripts/evaluate_senter.py --models rule runs/my_run/model-best --pmc_eval_dir corpus/validation
License
MIT. See LICENSE.
Metadata
Release files for biosenter 0.2.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 | |
|---|---|---|---|
| biosenter-0.2.0.tar.gz | 3.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| biosenter-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 6.9 MB
Release files / biosenter-0.2.0.tar.gz
| Download URL | biosenter-0.2.0.tar.gz |
|---|---|
| Size | 3.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b90bd2466bd55eff6b5eacfc3295b4f1869deb37600498aeb4171ddf2f7ebe5
|
|
BLAKE2b-256 checksum How to use checksums |
61ea15e06869a32b718d43b3cb4997b6fdee599f573cb20be1761a3b4cd720c4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency logRelease files / biosenter-0.2.0-py3-none-any.whl
| Download URL | biosenter-0.2.0-py3-none-any.whl |
|---|---|
| Size | 3.4 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7b5d44bc14f7bdcb6897c06d8facabd893d553486b8345704272df744251f444
|
|
BLAKE2b-256 checksum How to use checksums |
abaac86b9004d10cf370a3223c1cf70f2c443422d283cf59634cc547cb9352c8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 22, 2026.
Transparency log