Syntagma Tokenizer#

This tutorial will show an example of how to apply syntagma tokenizer medkit operation on a text document.

Loading a text document#

For beginners, let’s load a text file using the TextDocument class:

# 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"))

The full raw text can be accessed through the text attribute:

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 syntagma definition rules#

To split the text document into medkit segments corresponding to a text part, we have to define a set of rules. These rules allow the operation to split the text based on regular expressions rules.

from medkit.text.segmentation.syntagma_tokenizer import SyntagmaTokenizer

separators = (
    "(?<=\. )[\w\d]+",     # Trigger: starts after a dot and space
    "(?<=\n)[\w\d]+",      # Trigger: starts after a newline
    "(?<=: )\w+",          # Trigger: starts after :
    "(?<= )mais\s+(?=\w)", # Trigger: starts with 'mais' if space before and after
    "(?<= )sans\s+(?=\w)", # Trigger: starts with 'sans' if space before and after
    "(?<= )donc\s+(?=\w)", # Trigger: starts with 'donc' if space before and after
)

tokenizer = SyntagmaTokenizer(separators)

The syntagmas definition is a list of regular expressions allowing to trigger the start of a new syntagma.

As all operations, SyntagmaTokenizer defines a run() method. This method returns a list of Segment objects (a Segment is a TextAnnotation that represents a portion of a document’s full raw text). As input, it also expects a list of Segment objects. Here, we can pass a special segment containing the whole raw text of the document, that we can retrieve through the raw_segment attribute of TextDocument:

syntagmas = tokenizer.run([doc.raw_segment])

print(f"Number of detected syntagmas: {len(syntagmas)}")
print(f"Syntagmas label: {syntagmas[0].label}\n")

for syntagma in syntagmas:
    print(f"{syntagma.spans}\t{syntagma.text!r}")
Number of detected syntagmas: 39
Syntagmas label: syntagma

[Span(start=0, end=11)]	'SUBJECTIF :'
[Span(start=12, end=64)]	"Cette femme blanche de 23 ans se plaint d'allergies."
[Span(start=65, end=137)]	"Elle avait l'habitude d'avoir des allergies lorsqu'elle vivait à Seattle"
[Span(start=138, end=178)]	"mais elle pense qu'elles sont pires ici."
[Span(start=179, end=233)]	'Dans le passé, elle a essayé le Claritin et le Zyrtec.'
[Span(start=234, end=284)]	'Les deux ont fonctionné pendant une courte période'
[Span(start=285, end=335)]	'mais ont ensuite semblé perdre de leur efficacité.'
[Span(start=336, end=369)]	'Elle a également utilisé Allegra.'
[Span(start=370, end=449)]	"Elle l'a utilisé l'été dernier et a recommencé à le faire il y a deux semaines."
[Span(start=450, end=489)]	'Il ne semble pas fonctionner très bien.'
[Span(start=490, end=538)]	'Elle a utilisé des vaporisateurs en vente libre,'
[Span(start=539, end=587)]	'mais pas de vaporisateurs nasaux sur ordonnance.'
[Span(start=588, end=607)]	"Elle a de l'asthme,"
[Span(start=608, end=721)]	"mais n'a pas besoin de prendre des médicaments tous les jours pour cela et ne pense pas que son asthme s'aggrave."
[Span(start=723, end=736)]	'MÉDICAMENTS :'
[Span(start=737, end=804)]	"Son seul médicament est actuellement Ortho Tri-Cyclen et l'Allegra."
[Span(start=806, end=817)]	'ALLERGIES :'
[Span(start=818, end=867)]	"Elle n'a pas d'allergies médicamenteuses connues."
[Span(start=869, end=886)]	'EXAMEN PHYSIQUE :'
[Span(start=887, end=902)]	'Signes vitaux :'
[Span(start=903, end=954)]	'Poids de 59.3 kilos et pression sanguine de 124/78.'
[Span(start=955, end=985)]	'Tete/Yeux/Oreilles/Nez/Gorge :'
[Span(start=986, end=1025)]	'Sa gorge était légèrement érythémateuse'
[Span(start=1026, end=1039)]	'sans exsudat.'
[Span(start=1040, end=1089)]	'La muqueuse nasale était érythémateuse et enflée.'
[Span(start=1090, end=1127)]	'Seul un drainage clair était visible.'
[Span(start=1128, end=1151)]	'Les TM étaient claires.'
[Span(start=1152, end=1157)]	'Cou :'
[Span(start=1158, end=1182)]	'Souple sans adénopathie.'
[Span(start=1183, end=1192)]	'Poumons :'
[Span(start=1193, end=1201)]	'Dégagés.'
[Span(start=1203, end=1215)]	'EVALUATION :'
[Span(start=1216, end=1235)]	'Rhinite allergique.'
[Span(start=1237, end=1295)]	"PLAN :\n- Elle va réessayer le Zyrtec au lieu de l'Allegra."
[Span(start=1296, end=1343)]	"Une autre option sera d'utiliser la loratadine."
[Span(start=1344, end=1377)]	'Elle ne pense pas être remboursée'
[Span(start=1378, end=1439)]	'donc ça pourrait être moins cher.\n- Echantillons de Nasonex :'
[Span(start=1440, end=1502)]	'deux pulvérisations dans chaque narine pendant trois semaines.'
[Span(start=1503, end=1542)]	'Une ordonnance a également été rédigée.'

As you can see, the text have been split into 39 medkit segments which default label is "SYNTAGMA". Corresponding spans reflect the position of the text in the document’s full raw text.

Using a yaml definition file#

We have seen how to write rules programmatically.

However, it is also possible to load a yaml file containing all your rules.

First, let’s create the yaml file based on previous steps.

import pathlib

filepath = pathlib.Path("syntagma.yml")

SyntagmaTokenizer.save_syntagma_definition(
    syntagma_seps=separators,
    filepath=filepath,
    encoding='utf-8')

with open(filepath, 'r') as f:
    print(f.read())
syntagmas:
  separators:
  - (?<=\. )[\w\d]+
  - '(?<=

    )[\w\d]+'
  - '(?<=: )\w+'
  - (?<= )mais\s+(?=\w)
  - (?<= )sans\s+(?=\w)
  - (?<= )donc\s+(?=\w)

Now, we will see how to initialize the SyntagmaTokenizer operation for using this yaml file.

# Use tokenizer initialized using a yaml file
from medkit.text.segmentation import SyntagmaTokenizer

separators = SyntagmaTokenizer.load_syntagma_definition(filepath)

print("separators = ")
for sep in separators:
    print(f"- {sep!r}")

      
tokenizer = SyntagmaTokenizer(separators=separators)
separators = 
- '(?<=\\. )[\\w\\d]+'
- '(?<=\n)[\\w\\d]+'
- '(?<=: )\\w+'
- '(?<= )mais\\s+(?=\\w)'
- '(?<= )sans\\s+(?=\\w)'
- '(?<= )donc\\s+(?=\\w)'

Now let’s run the operation. We can observe that the results are the same.

syntagmas = tokenizer.run([doc.raw_segment])

print(f"Number of detected syntagmas: {len(syntagmas)}\n")

for syntagma in syntagmas:
    print(f"{syntagma.spans}\t{syntagma.text!r}")
Number of detected syntagmas: 39

[Span(start=0, end=11)]	'SUBJECTIF :'
[Span(start=12, end=64)]	"Cette femme blanche de 23 ans se plaint d'allergies."
[Span(start=65, end=137)]	"Elle avait l'habitude d'avoir des allergies lorsqu'elle vivait à Seattle"
[Span(start=138, end=178)]	"mais elle pense qu'elles sont pires ici."
[Span(start=179, end=233)]	'Dans le passé, elle a essayé le Claritin et le Zyrtec.'
[Span(start=234, end=284)]	'Les deux ont fonctionné pendant une courte période'
[Span(start=285, end=335)]	'mais ont ensuite semblé perdre de leur efficacité.'
[Span(start=336, end=369)]	'Elle a également utilisé Allegra.'
[Span(start=370, end=449)]	"Elle l'a utilisé l'été dernier et a recommencé à le faire il y a deux semaines."
[Span(start=450, end=489)]	'Il ne semble pas fonctionner très bien.'
[Span(start=490, end=538)]	'Elle a utilisé des vaporisateurs en vente libre,'
[Span(start=539, end=587)]	'mais pas de vaporisateurs nasaux sur ordonnance.'
[Span(start=588, end=607)]	"Elle a de l'asthme,"
[Span(start=608, end=721)]	"mais n'a pas besoin de prendre des médicaments tous les jours pour cela et ne pense pas que son asthme s'aggrave."
[Span(start=723, end=736)]	'MÉDICAMENTS :'
[Span(start=737, end=804)]	"Son seul médicament est actuellement Ortho Tri-Cyclen et l'Allegra."
[Span(start=806, end=817)]	'ALLERGIES :'
[Span(start=818, end=867)]	"Elle n'a pas d'allergies médicamenteuses connues."
[Span(start=869, end=886)]	'EXAMEN PHYSIQUE :'
[Span(start=887, end=902)]	'Signes vitaux :'
[Span(start=903, end=954)]	'Poids de 59.3 kilos et pression sanguine de 124/78.'
[Span(start=955, end=985)]	'Tete/Yeux/Oreilles/Nez/Gorge :'
[Span(start=986, end=1025)]	'Sa gorge était légèrement érythémateuse'
[Span(start=1026, end=1039)]	'sans exsudat.'
[Span(start=1040, end=1089)]	'La muqueuse nasale était érythémateuse et enflée.'
[Span(start=1090, end=1127)]	'Seul un drainage clair était visible.'
[Span(start=1128, end=1151)]	'Les TM étaient claires.'
[Span(start=1152, end=1157)]	'Cou :'
[Span(start=1158, end=1182)]	'Souple sans adénopathie.'
[Span(start=1183, end=1192)]	'Poumons :'
[Span(start=1193, end=1201)]	'Dégagés.'
[Span(start=1203, end=1215)]	'EVALUATION :'
[Span(start=1216, end=1235)]	'Rhinite allergique.'
[Span(start=1237, end=1295)]	"PLAN :\n- Elle va réessayer le Zyrtec au lieu de l'Allegra."
[Span(start=1296, end=1343)]	"Une autre option sera d'utiliser la loratadine."
[Span(start=1344, end=1377)]	'Elle ne pense pas être remboursée'
[Span(start=1378, end=1439)]	'donc ça pourrait être moins cher.\n- Echantillons de Nasonex :'
[Span(start=1440, end=1502)]	'deux pulvérisations dans chaque narine pendant trois semaines.'
[Span(start=1503, end=1542)]	'Une ordonnance a également été rédigée.'