File size: 4,587 Bytes
b2e9550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8bd90d
 
 
 
 
 
 
 
 
 
 
b2e9550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
"""Deterministic study, evidence-domain and population-level classification."""
from __future__ import annotations

import re


_PUBLICATION_TYPE_RULES: list[tuple[str, tuple[str, ...]]] = [
    ("meta_analysis", ("meta-analysis", "meta analysis")),
    ("systematic_review", ("systematic review",)),
    ("randomized_controlled_trial", ("randomized controlled trial", "randomised controlled trial")),
    ("controlled_clinical_trial", ("controlled clinical trial", "clinical trial")),
    ("cohort", ("cohort studies", "cohort study")),
    ("case_control", ("case-control studies", "case control study")),
    ("cross_sectional", ("cross-sectional studies", "cross sectional study")),
    ("case_report", ("case reports", "case report")),
    ("narrative_review", ("review",)),
]

_TEXT_RULES: list[tuple[str, re.Pattern[str]]] = [
    ("meta_analysis", re.compile(r"\bmeta-analysis\b", re.I)),
    ("systematic_review", re.compile(r"\bsystematic review\b", re.I)),
    ("randomized_controlled_trial", re.compile(r"\brandomi[sz]ed\b.*\b(?:placebo|controlled|trial)\b|\bdouble-blind\b", re.I)),
    ("controlled_clinical_trial", re.compile(r"\bclinical trial\b|\bcontrolled trial\b", re.I)),
    ("cohort", re.compile(r"\bprospective cohort\b|\bretrospective cohort\b", re.I)),
    ("case_control", re.compile(r"\bcase-control\b", re.I)),
    ("cross_sectional", re.compile(r"\bcross-sectional\b", re.I)),
    ("case_report", re.compile(r"\bcase report\b", re.I)),
    ("pharmacokinetic_study", re.compile(r"\bpharmacokinetic\b|\bAUC\b|\bCmax\b|\bclearance\b", re.I)),
    ("animal_experiment", re.compile(r"\b(?:mice|mouse|rats?|murine|rodents?|rabbits?|dogs?|swine)\b", re.I)),
    ("in_vitro", re.compile(r"\bin vitro\b|\bcell lines?\b|\bcultured cells?\b", re.I)),
]


def classify_study_type(publication_types: list[str], title: str, abstract: str) -> str:
    normalized = [value.casefold() for value in publication_types]
    for study_type, labels in _PUBLICATION_TYPE_RULES:
        if any(any(label in value for label in labels) for value in normalized):
            return study_type

    text = f"{title}\n{abstract}"
    for study_type, pattern in _TEXT_RULES:
        if pattern.search(text):
            return study_type
    return "unknown"


def is_secondary_research(study_type: str) -> bool:
    return study_type in {"meta_analysis", "systematic_review", "narrative_review"}


def classify_population_level(title: str, abstract: str, study_type: str) -> str:
    text = f"{title}\n{abstract}"
    animal = bool(
        re.search(
            r"\b(?:mice|mouse|rats?|murine|rodents?|"
            r"rabbits?|dogs?|swine|animals?|"
            r"animal models?|lab animal studies?|"
            r"laboratory animal studies?|"
            r"laboratory animals?)\b",
            text,
            re.I,
        )
    )
    invitro = bool(re.search(r"\bin vitro\b|\bcell lines?\b|\bcultured cells?\b", text, re.I))
    human = bool(re.search(r"\b(?:participants?|patients?|subjects?|volunteers?|adults?|children|students?|women|men|elderly|humans?)\b", text, re.I))

    levels = [name for name, present in (("human", human), ("animal", animal), ("in_vitro", invitro)) if present]
    if len(levels) > 1:
        return "mixed"
    if levels:
        return levels[0]
    if study_type in {"randomized_controlled_trial", "controlled_clinical_trial", "nonrandomized_intervention", "cohort", "case_control", "cross_sectional", "case_report", "pharmacokinetic_study"}:
        return "human"
    if study_type == "animal_experiment":
        return "animal"
    if study_type == "in_vitro":
        return "in_vitro"
    return "not_applicable" if is_secondary_research(study_type) else "mixed"


def classify_evidence_domain(question: str | None, title: str, abstract: str) -> str:
    text = " ".join(filter(None, [question, title, abstract]))
    interaction = bool(re.search(r"\binteraction|herb[- ]drug|CYP\d|cytochrome|warfarin|pharmacokinetic\b", text, re.I))
    safety = bool(re.search(r"\bsafety|adverse|toxicity|tolerability|harm|hepatotox|nephrotox\b", text, re.I))
    mechanism = bool(re.search(r"\bmechanism|pathway|inhibit(?:s|ed|ion)?|activate(?:s|d|ion)?|enzyme|receptor\b", text, re.I))
    efficacy = bool(re.search(r"\befficacy|effectiveness|improv|reduc|increase|decrease|benefit|outcome\b", text, re.I))

    active = [name for name, present in (("interaction", interaction), ("safety", safety), ("mechanism", mechanism), ("efficacy", efficacy)) if present]
    if len(active) > 1:
        return "mixed"
    return active[0] if active else "mixed"