Document splitter
Contents
Document splitter#
This tutorial will show an example of how to split a document using its sections as a reference.
See also
We combine some operations like section tokenizer, regexp matcher and custom operation. Please see the other examples for more information.
Adding annotations in a document#
Let’s detect the sections and add some annotations using medkit operations.
# You can download the file available in source code
# !wget https://raw.githubusercontent.com/TeamHeka/medkit/main/docs/data/text/1.txt
from pathlib import Path
from medkit.core.text import TextDocument
doc = TextDocument.from_file(Path("../../data/text/1.txt"))
print(doc.text)
SUBJECTIF : Cette femme blanche de 23 ans se plaint d'allergies. Elle avait l'habitude d'avoir des allergies lorsqu'elle vivait à Seattle mais elle pense qu'elles sont pires ici. Dans le passé, elle a essayé le Claritin et le Zyrtec. Les deux ont fonctionné pendant une courte période mais ont ensuite semblé perdre de leur efficacité. Elle a également utilisé Allegra. Elle l'a utilisé l'été dernier et a recommencé à le faire il y a deux semaines. Il ne semble pas fonctionner très bien. Elle a utilisé des vaporisateurs en vente libre, mais pas de vaporisateurs nasaux sur ordonnance. Elle a de l'asthme, mais n'a pas besoin de prendre des médicaments tous les jours pour cela et ne pense pas que son asthme s'aggrave.
MÉDICAMENTS : Son seul médicament est actuellement Ortho Tri-Cyclen et l'Allegra.
ALLERGIES : Elle n'a pas d'allergies médicamenteuses connues.
EXAMEN PHYSIQUE :
Signes vitaux : Poids de 59.3 kilos et pression sanguine de 124/78.
Tete/Yeux/Oreilles/Nez/Gorge : Sa gorge était légèrement érythémateuse sans exsudat. La muqueuse nasale était érythémateuse et enflée. Seul un drainage clair était visible. Les TM étaient claires.
Cou : Souple sans adénopathie.
Poumons : Dégagés.
EVALUATION : Rhinite allergique.
PLAN :
- Elle va réessayer le Zyrtec au lieu de l'Allegra. Une autre option sera d'utiliser la loratadine. Elle ne pense pas être remboursée donc ça pourrait être moins cher.
- Echantillons de Nasonex : deux pulvérisations dans chaque narine pendant trois semaines. Une ordonnance a également été rédigée.
Defining the operations
from medkit.text.ner import RegexpMatcher, RegexpMatcherRule
from medkit.text.segmentation import SectionTokenizer
# Define a section tokenizer
# The section tokenizer uses a dictionary with keywords to identify sections
section_dict = {
"patient": ["SUBJECTIF"],
"traitement": ["MÉDICAMENTS", "PLAN"],
"allergies": ["ALLERGIES"],
"examen clinique": ["EXAMEN PHYSIQUE"],
"diagnostique": ["EVALUATION"],
}
section_tokenizer = SectionTokenizer(section_dict=section_dict)
# Define a NER operation to create 'problem', and 'treatment' entities
regexp_rules = [
RegexpMatcherRule(regexp=r"\ballergies\b", label="problem"),
RegexpMatcherRule(regexp=r"\basthme\b", label="problem"),
RegexpMatcherRule(regexp=r"\ballegra\b", label="treatment", case_sensitive=False),
RegexpMatcherRule(regexp=r"\bvaporisateurs\b", label="treatment"),
RegexpMatcherRule(regexp=r"\bloratadine\b", label="treatment", case_sensitive=False),
RegexpMatcherRule(regexp=r"\bnasonex\b", label="treatment", case_sensitive=False),
]
regexp_matcher = RegexpMatcher(rules=regexp_rules)
We can now annotate the document
# Detect annotations
sections = section_tokenizer.run([doc.raw_segment])
entities = regexp_matcher.run([doc.raw_segment])
# Annotate
for ann in sections + entities:
doc.anns.add(ann)
print(f"The document contains {len(sections)} sections and {len(entities)} entities\n")
The document contains 6 sections and 12 entities
Split the document by sections#
Once annotated, we can use the medkit operation DocumentSplitter
to create smaller versions of the document using the sections.
By default, since its entity_labels
, attr_labels
, and relation_labels
are set to None
, all annotations will be in the resulting documents. You can select the annotations using their labels.
from medkit.text.postprocessing import DocumentSplitter
doc_splitter = DocumentSplitter(segment_label="section", # segments of reference
entity_labels=["treatment","problem"],# entities to include
attr_labels=[], # without attrs
relation_labels=[], #without relations
)
new_docs = doc_splitter.run([doc])
print(f"The document was divided into {len(new_docs)} documents\n")
The document was divided into 6 documents
Each document contains entities and attributes from the source segment; below, we visualize the new documents via displacy utils.
from spacy import displacy
from medkit.text.spacy.displacy_utils import medkit_doc_to_displacy
options_displacy = dict(colors={'treatment': "#85C1E9", "problem": "#ff6961"})
for new_doc in new_docs:
print(f"New document from the section called '{new_doc.metadata['name']}'")
# convert new document to displacy
displacy_data = medkit_doc_to_displacy(new_doc)
displacy.render(displacy_data, manual=True, style="ent", options=options_displacy)
New document from the section called 'patient'
New document from the section called 'traitement'
New document from the section called 'allergies'
New document from the section called 'examen clinique'
Signes vitaux : Poids de 59.3 kilos et pression sanguine de 124/78.
Tete/Yeux/Oreilles/Nez/Gorge : Sa gorge était légèrement érythémateuse sans exsudat. La muqueuse nasale était érythémateuse et enflée. Seul un drainage clair était visible. Les TM étaient claires.
Cou : Souple sans adénopathie.
Poumons : Dégagés.
New document from the section called 'diagnostique'
New document from the section called 'traitement'
- Elle va réessayer le Zyrtec au lieu de l' Allegra treatment . Une autre option sera d'utiliser la loratadine treatment . Elle ne pense pas être remboursée donc ça pourrait être moins cher.
- Echantillons de Nasonex treatment : deux pulvérisations dans chaque narine pendant trois semaines. Une ordonnance a également été rédigée.