Ejemplo n.º 1
0
def LF_positive_left(span):
    left = get_left_span(span, window=10)
    rgx = r'''\b(positive for|suggestive of|due to|shows)\b'''
    trigger = match_regex(rgx, left)
    if not trigger:
        return ABSTAIN
    left = get_left_span(trigger, window=50)
    m = re.search(r'''\b(no|not)\b''', left.text, re.I)
    return NON_NEGATED if not re.search(r'''\b(no|not)\b''', left.text, re.I) else ABSTAIN
Ejemplo n.º 2
0
def LF_head_word(span):
    rgx = re.compile(
        r'''^(no|not|never|cannot|negative for|negative|neg|absent|ruled out|without|absence of|den(y|ied|ies))\b''',
        re.I)
    left = get_left_span(span, span.sentence)
    n = len(left.get_attrib_span('words'))
    return NEGATED if rgx.search(left.text.strip()) else ABSTAIN
Ejemplo n.º 3
0
def LF_left_context(span):
    left = get_left_span(span, span.sentence, window=6)

    # negated mentions
    neg_rgxes = [
        r'''\b(no|did not have|neg(ative)* for) (mild|slight|minimal|severe|moderate|extensive|marked|extreme|significant|progressive)\b''',
        r'''\b(no|did not have|neg(ative)* for) (known|evidence of|evidence)\b'''
    ]
    neg_rgxes = [re.compile(rgx, re.I) for rgx in neg_rgxes]

    for rgx in neg_rgxes:
        trigger = match_regex(rgx, left)
        if trigger and token_distance(trigger, span) <= 2:
            return NEGATED

    # positive mentions
    pos_regxes = [
        r'''(cannot exclude|does not become|may not|possible|evaluate for|suggests)''',  # hedged
        r'''(mild|minimal|severe|moderate|extensive|coarse|marked|extreme|significant|trivial|progressive|slight)(ly)*''',
        # severity
        r'''(diagnosed with|known to have|known|non-specific|presented|secondary to|treated for|acute onset|improving|improved|improvement|involvement|resolved|consistent with|showed|presumed|suspicious for|check for|revealed|new onset|were noted|found to be|demonstrate(d)*)''',
        # present now
        r'''\b((in|de)creas(e|ed|ing)|up|down)\b''',  # LF_change_words_left
        r'''(s/p|status[- ]post)''',

    ]
    pos_regxes = [re.compile(rgx, re.I) for rgx in pos_regxes]

    for rgx in pos_regxes:
        if rgx.search(span.text):
            return NON_NEGATED
    return ABSTAIN
Ejemplo n.º 4
0
def LF_definite_left_0(span, negex):
    left = get_left_span(span, span.sentence, window=6)
    trigger = match_regex(negex.rgxs['definite']['left'], left)
    if not trigger:
        return ABSTAIN
    dist = token_distance(trigger, span)
    return NEGATED if dist == 0 else ABSTAIN
Ejemplo n.º 5
0
def LF_pseudo_left_exp(span, negex):
    pseudo_rgx = re.compile(
        r'''\b(exclude|improvement of|performed|be quantified|not limited to|be adequately assessed|do not indicate|significant change)\b''',
        re.I)
    rgx = negex.rgxs['definite']['left']
    text = get_left_span(span, span.sentence, window=6).text
    return NON_NEGATED if rgx.search(text) and pseudo_rgx.search(text) else ABSTAIN
Ejemplo n.º 6
0
def LF_relative(span):
    """Context includes any familial mention (e.g., mother father)"""
    left = get_left_span(span, span.sentence, window=6)
    right = get_right_span(span, span.sentence, window=6)
    left_trigger = match_regex(rgx_relatives, left)
    right_trigger = match_regex(rgx_relatives, right)
    return OTHER if left_trigger or right_trigger else PATIENT
Ejemplo n.º 7
0
def LF_pseudo_negation_rule_out(span):
    left_rgx = r'''(cannot|does not|doesn't) rule[s]* out'''
    left = get_left_span(span)
    trigger = match_regex(left_rgx, left)
    if not trigger or token_distance(trigger, span) > 5:
        return ABSTAIN
    return NON_NEGATED if re.search(r'''(cannot|does not|doesn't)''',
                                    trigger.text, re.I) else NEGATED
Ejemplo n.º 8
0
def LF_header(span, negex):
    """All spans under Family History are assumed to refer to family"""
    rgx = re.compile(r'''(family history[:]*|family hx)\b''', re.I)
    left = get_left_span(span, span.sentence, window=6)
    trigger = match_regex(rgx, left)

    if trigger:
        # check for negation ("no family history")
        neg = match_regex(negex.rgxs['definite']['left'],
                          get_left_span(trigger, window=2))
        return ABSTAIN if neg else OTHER

    if 'section' in span.props:
        header = span.props['section']
        if header and rgx.search(header.text):
            return OTHER
    return ABSTAIN
Ejemplo n.º 9
0
def LF_social(span):
    rgx_social = re.compile(r'''\b(friend(s)*|roomate(s)*|passenger(s)*)\b''',
                            re.I)
    left = get_left_span(span, span.sentence, window=6)
    right = get_right_span(span, span.sentence, window=6)
    left_trigger = match_regex(rgx_social, left)
    right_trigger = match_regex(rgx_social, right)
    return OTHER if left_trigger or right_trigger else ABSTAIN
Ejemplo n.º 10
0
def LF_header_break_negation(span, negex):
    left = get_left_span(span)
    trigger = match_regex(negex.rgxs['definite']['left'], left)
    if not trigger:
        return ABSTAIN
    btw = get_between_span(trigger, span)
    if not btw:
        return ABSTAIN
    rgx = r'''\s{2,}((?:(?:[A-Z][A-Za-z]+\s){1,4}(?:[A-Za-z]+))[:])'''
    return NON_NEGATED if re.search(rgx, btw.text) else ABSTAIN
Ejemplo n.º 11
0
def LF_probable_left_4_6(span, negex):
    left = get_left_span(span, span.sentence, window=6)
    trigger = match_regex(negex.rgxs['probable']['left'], left)
    if not trigger:
        return ABSTAIN
    dist = token_distance(trigger, span)
    right = get_right_span(trigger, window=2)
    if pseudo_negation.search(right.text):
        return ABSTAIN
    return NEGATED if (dist >= 4 and dist <= 6) else ABSTAIN
Ejemplo n.º 12
0
def LF_temporal_left(span):
    left = get_left_span(span, window=100)
    rgx = re.compile(
        r'(no|(does|has) not|not had|without|denies) (history of|prior|chronic|residual|occasional|restarted|post-surgical changes|again noted|immediate(ly)*|remained on)',
        re.I)
    match = rgx.search(left.text)
    if not match:
        return ABSTAIN
    if re.search(r'''(no|(does|has) not|not had|without|denies)\b''', match.group(), re.I):
        return NEGATED
    else:
        return NON_NEGATED
Ejemplo n.º 13
0
def LF_definite_left_7_10(span, negex):
    left = get_left_span(span, span.sentence)
    trigger = match_regex(negex.rgxs['definite']['left'], left)
    if not trigger:
        return ABSTAIN
    dist = token_distance(trigger, span)

    right = get_right_span(trigger, window=2)
    if pseudo_negation.search(right.text):
        return ABSTAIN

    return NEGATED if (dist >= 7 and dist <= 10) else ABSTAIN
Ejemplo n.º 14
0
def LF_definite_left_list(span, negex):
    left = get_left_span(span, span.sentence, window=100)
    trigger = match_regex(negex.rgxs['definite']['left'], left)
    if not trigger:
        return ABSTAIN
    dist = token_distance(trigger, span)
    btw = get_between_span(trigger, span)

    right = get_right_span(trigger, window=2)
    if pseudo_negation_rgx.search(right.text):
        return ABSTAIN

    return NEGATED if dist <= 10 and btw and len(re.findall(r'''[,;]''', btw.text)) > 1 else ABSTAIN
Ejemplo n.º 15
0
def LF_denies_list(span):
    """ Patient denies X,Y,Z. """
    rgx = re.compile(r'''\b(den(ying|y|ies|ied))\b''', re.I)
    left = get_left_span(span, window=100)
    trigger = match_regex(rgx, left)
    if not trigger:
        return ABSTAIN

    btw = get_between_span(trigger, span)
    if not btw:
        return ABSTAIN

    n = len(re.findall(r'''[,;/]''', btw.text))
    return NEGATED if n >= 1 else ABSTAIN
Ejemplo n.º 16
0
def LF_pseudo_negation_exclusion(span):
    left_rgx = r'''(inadequate\s+to|does\s+not|cannot|can't)\s+exclude'''
    right_rgx = r'''(cannot\s+be|not\s+be|doesn't|not|to)\s+exclude[d]*'''

    left = get_left_span(span)
    trigger = match_regex(left_rgx, left)
    if trigger and token_distance(trigger, span) <= 3:
        return NON_NEGATED

    right = get_right_span(span)
    trigger = match_regex(right_rgx, right)
    if trigger and token_distance(trigger, span) <= 3:
        return NON_NEGATED

    return ABSTAIN
Ejemplo n.º 17
0
    def _apply_lfs(self, span, sentence, ngrams):
        """
        Apply NegEx labeling functions.
        TODO: Window size is fixed here, choices of 5-8 perform well
        """
        left = get_left_span(span, sentence, window=ngrams)
        right = get_right_span(span, sentence, window=ngrams)

        L = []
        for name in sorted(self.negex.rgxs):
            for cxt in sorted(self.negex.rgxs[name]):
                v = 0
                text = left.text if cxt == 'left' else right.text
                if self.negex.rgxs[name][cxt].search(text):
                    v = self.class_map[name]
                L.append(v)
        return np.array(L)
Ejemplo n.º 18
0
def LF_pseudo_left_expanded(span, negex):
    pseudo_rgxs = [
        r'''\b((significant )*(change[s]* in|improvement))\b''',
        r'''\b((in|de)creas(e|ed|ing)|up|down)\b'''
    ]
    left = get_left_span(span)
    trigger = match_regex(negex.rgxs['definite']['left'], left)
    if not trigger or token_distance(trigger, span) > 20:
        return ABSTAIN

    btw = get_between_span(span, trigger)
    if not btw:
        return ABSTAIN

    for rgx in pseudo_rgxs:
        if re.search(rgx, btw.text, re.I):
            return NON_NEGATED

    return ABSTAIN
Ejemplo n.º 19
0
    def negation(self, span, category, direction, window=3):
        """
        Return any matched negex phrases

        :param span:
        :param category:
        :param direction:
        :param window:
        :return:
        """
        rgx = self.rgxs[category][direction]
        if not rgx.pattern:
            return None

        cxt = get_left_span(span, window=window) if direction == 'left' \
            else get_right_span(span, window=window)

        m = rgx.findall(cxt.text)
        return m if m else None
Ejemplo n.º 20
0
def LF_terminator_word_left(span):
    trigger_rgx = re.compile(
        r'''(no|not|never|cannot|negative for|negative|neg|absent|ruled out|without|absence of|den(y|ied|ies))\b''',
        re.I)
    rgx = re.compile(r'''\b(but|after|post|prior|before|during|rather than)\b|\n|[:;]''', re.I)
    # find closest trigger word
    text = get_left_span(span, span.sentence, window=6).text
    matches = [m for m in trigger_rgx.finditer(span.sentence.text) if m.span()[-1] < span.char_start]
    start = len(text)
    trigger = None
    for m in matches:
        if trigger:
            d1 = start - trigger.span()[-1]
            d2 = start - m.span()[-1]
            if d2 < d1:
                trigger = m
        else:
            trigger = m
    # does a terminator word occur between?
    if trigger:
        window = text[trigger.span()[-1]:]
        return NON_NEGATED if rgx.search(window) else ABSTAIN
    return ABSTAIN
Ejemplo n.º 21
0
def LF_severe(span):
    rgx = r'''(sharp|knife-like|significant|extensive|extreme|(marked|severe)(ly)*|severity)'''
    text = get_left_span(span, span.sentence, window=6).text
    return SEVERE if re.search(rgx, text, re.I) else ABSTAIN
Ejemplo n.º 22
0
def LF_moderate(span):
    rgx = r'''((moderate|mild)(ly)*|large)'''
    text = get_left_span(span, span.sentence, window=6).text
    return MODERATE if re.search(rgx, text, re.I) else ABSTAIN
Ejemplo n.º 23
0
def LF_slight(span):
    rgx = r'''\b((slight|minimal)(ly)*|trace|minor|trivial|little|partial|min)\b'''
    text = get_left_span(span, span.sentence, window=6).text
    return SLIGHT if re.search(rgx, text, re.I) else ABSTAIN
Ejemplo n.º 24
0
def LF_history_of(span):
    rgx = r'''\bfamily (history of|hx)'''
    text = get_left_span(span, span.sentence, window=6).text
    return OTHER if re.search(rgx, text.strip(), re.I) else ABSTAIN
Ejemplo n.º 25
0
def LF_ext_family(span):
    rgx = re.compile(r'''\b(spouse|wife|husband)\b''', re.I)
    text = get_left_span(span, span.sentence, window=6).text
    return OTHER if rgx.search(text) else ABSTAIN
Ejemplo n.º 26
0
def LF_donor(span):
    rgx = r'''\b(donor)\b'''
    text = get_left_span(span, span.sentence, window=6).text
    return OTHER if re.search(rgx, span.sentence.text.strip(),
                              re.I) else ABSTAIN
Ejemplo n.º 27
0
def LF_probable_left(span, negex):
    text = get_left_span(span, span.sentence, window=6).text
    rgx = negex.rgxs['probable']['left']
    if pseudo_negation(span):
        return ABSTAIN
    return NEGATED if rgx.search(text) else ABSTAIN
Ejemplo n.º 28
0
def LF_pseudo_left(span, negex):
    text = get_left_span(span, span.sentence, window=6).text
    rgx = negex.rgxs['pseudo']['left']
    return NON_NEGATED if rgx.search(text) else ABSTAIN
Ejemplo n.º 29
0
def LF_left_punct(span):
    cspan = get_containing_span(span)
    left = get_left_span(cspan, span.sentence, window=1)
    if left.text == '+':
        return NON_NEGATED
    return ABSTAIN
Ejemplo n.º 30
0
def LF_verb_left(span):
    left = get_left_span(span, span.sentence, window=50).text
    rgx = r'''((no|not|(den(y|ies|ied|ying))) )*(\w+ ){1,}(is a|is|will be|are)$'''
    m = re.search(rgx, left, re.I)
    return NON_NEGATED if m and not re.search(r'''\b(no|not|den(y|ies|ied|ying))\b''', m.group(), re.I) else ABSTAIN