Skip to content

Dosage

Bases: object

Container for drug dosage information

Source code in miade/dosage.py
class Dosage(object):
    """
    Container for drug dosage information
    """

    def __init__(
        self,
        dose: Optional[Dose],
        duration: Optional[Duration],
        frequency: Optional[Frequency],
        route: Optional[Route],
        text: Optional[str] = None,
    ):
        self.text = text
        self.dose = dose
        self.duration = duration
        self.frequency = frequency
        self.route = route

    @classmethod
    def from_doc(cls, doc: Doc, calculate: bool = True):
        """
        Parses dosage from a spacy doc object.

        Args:
            doc (Doc): Spacy doc object with processed dosage text.
            calculate (bool, optional): Whether to calculate duration if total and daily dose is given. Defaults to True.

        Returns:
            An instance of the class with the parsed dosage information.

        """
        quantities = []
        units = []
        dose_start = 1000
        dose_end = 0
        daily_dose = None
        total_dose = None
        route_text = None
        duration_text = None

        for ent in doc.ents:
            if ent.label_ == "DOSAGE":
                if ent._.total_dose:
                    total_dose = float(ent.text)
                else:
                    quantities.append(ent.text)
                    # get span of full dosage string - not strictly needed but nice to have
                    if ent.start < dose_start:
                        dose_start = ent.start
                    if ent.end > dose_end:
                        dose_end = ent.end
            elif ent.label_ == "FORM":
                if ent._.total_dose:
                    # de facto unit is in total dose
                    units = [ent.text]
                else:
                    units.append(ent.text)
                    if ent.start < dose_start:
                        dose_start = ent.start
                    if ent.end > dose_end:
                        dose_end = ent.end
            elif ent.label_ == "DURATION":
                duration_text = ent.text
            elif ent.label_ == "ROUTE":
                route_text = ent.text

        dose = parse_dose(
            text=" ".join(doc.text.split()[dose_start:dose_end]),
            quantities=quantities,
            units=units,
            results=doc._.results,
        )

        frequency = parse_frequency(text=doc.text, results=doc._.results)

        route = parse_route(text=route_text, dose=dose)

        # technically not information recorded so will keep as an option
        if calculate:
            # if duration not given in text could extract this from total dose if given
            if total_dose is not None and dose is not None and doc._.results["freq"]:
                if dose.value is not None:
                    daily_dose = float(dose.value) * (round(doc._.results["freq"] / doc._.results["time"]))
                elif dose.high is not None:
                    daily_dose = float(dose.high) * (round(doc._.results["freq"] / doc._.results["time"]))

        duration = parse_duration(
            text=duration_text,
            results=doc._.results,
            total_dose=total_dose,
            daily_dose=daily_dose,
        )

        return cls(
            text=doc._.original_text,
            dose=dose,
            duration=duration,
            frequency=frequency,
            route=route,
        )

    def __str__(self):
        return f"{self.__dict__}"

    def __eq__(self, other):
        return self.__dict__ == other.__dict__

from_doc(doc, calculate=True) classmethod

Parses dosage from a spacy doc object.

Parameters:

Name Type Description Default
doc Doc

Spacy doc object with processed dosage text.

required
calculate bool

Whether to calculate duration if total and daily dose is given. Defaults to True.

True

Returns:

Type Description

An instance of the class with the parsed dosage information.

Source code in miade/dosage.py
@classmethod
def from_doc(cls, doc: Doc, calculate: bool = True):
    """
    Parses dosage from a spacy doc object.

    Args:
        doc (Doc): Spacy doc object with processed dosage text.
        calculate (bool, optional): Whether to calculate duration if total and daily dose is given. Defaults to True.

    Returns:
        An instance of the class with the parsed dosage information.

    """
    quantities = []
    units = []
    dose_start = 1000
    dose_end = 0
    daily_dose = None
    total_dose = None
    route_text = None
    duration_text = None

    for ent in doc.ents:
        if ent.label_ == "DOSAGE":
            if ent._.total_dose:
                total_dose = float(ent.text)
            else:
                quantities.append(ent.text)
                # get span of full dosage string - not strictly needed but nice to have
                if ent.start < dose_start:
                    dose_start = ent.start
                if ent.end > dose_end:
                    dose_end = ent.end
        elif ent.label_ == "FORM":
            if ent._.total_dose:
                # de facto unit is in total dose
                units = [ent.text]
            else:
                units.append(ent.text)
                if ent.start < dose_start:
                    dose_start = ent.start
                if ent.end > dose_end:
                    dose_end = ent.end
        elif ent.label_ == "DURATION":
            duration_text = ent.text
        elif ent.label_ == "ROUTE":
            route_text = ent.text

    dose = parse_dose(
        text=" ".join(doc.text.split()[dose_start:dose_end]),
        quantities=quantities,
        units=units,
        results=doc._.results,
    )

    frequency = parse_frequency(text=doc.text, results=doc._.results)

    route = parse_route(text=route_text, dose=dose)

    # technically not information recorded so will keep as an option
    if calculate:
        # if duration not given in text could extract this from total dose if given
        if total_dose is not None and dose is not None and doc._.results["freq"]:
            if dose.value is not None:
                daily_dose = float(dose.value) * (round(doc._.results["freq"] / doc._.results["time"]))
            elif dose.high is not None:
                daily_dose = float(dose.high) * (round(doc._.results["freq"] / doc._.results["time"]))

    duration = parse_duration(
        text=duration_text,
        results=doc._.results,
        total_dose=total_dose,
        daily_dose=daily_dose,
    )

    return cls(
        text=doc._.original_text,
        dose=dose,
        duration=duration,
        frequency=frequency,
        route=route,
    )