polars-cnlp adds clinical NLP and research-data-wrangling expressions directly to Polars.

Importing polars_cnlp registers two expression namespaces:

  • .cnlp — regex-based clinical concept matching and contextual interpretation;
  • .rdw — general research-data-wrangling string helpers.

The clinical NLP expressions can identify concepts, count mentions, determine whether concepts are affirmed, and return mention-level context such as assertion, temporality, and experiencer. Contextual processing supports both ConText-style and NegEx-style algorithms and can be customized with additional or replacement rules.

Installation

pip install polars-cnlp

Then import the package once to register the expression namespaces:

import polars as pl
import polars_cnlp  # noqa: F401  # registers .cnlp and .rdw namespaces

Note: Since we will not be using polars_cnlp directly, we’re adding the noqa to avoid any linters removing this import as it will appear ‘unused’.

Importing polars-cnlp

Import polars_cnlp before using the .cnlp or .rdw expression namespaces:

import polars as pl
import polars_cnlp  # noqa: F401  # registers .cnlp and .rdw namespaces

The polars_cnlp import registers the package’s Polars expression namespaces. After it has been imported, the namespaces are available on Polars expressions:

pl.col('note_text').cnlp.affirmed(r'\bpneumonia\b')
pl.col('code').rdw.starts_with_any(['J12', 'J13', 'J14'])

Although the polars_cnlp name does not need to be referenced directly afterward, the import itself is required for namespace registration.

For scripts and modules that use .cnlp or .rdw, explicitly importing polars_cnlp is recommended rather than relying on another module to have imported it previously.

Quick example

PNEUMONIA = r'\bpneumonia\b'

df = pl.DataFrame({'note_text': [
    'Patient has pneumonia.',
    'No pneumonia.',
    'Possible pneumonia.',
    'History of pneumonia.',
    'Family history of pneumonia.',
    'Patient has asthma.',
    None,
]})

result = df.with_columns(
    pl.col('note_text')
    .cnlp.affirmed(PNEUMONIA)
    .alias('pneumonia'),
)

affirmed() returns:

[True, False, False, False, False, None, None]

A concept is considered affirmed when the selected finding is:

assertion   = affirmed
temporality = current
experiencer = patient

Concept absence remains distinct from a non-affirmed mention: absent concepts return null, while mentioned but negated, possible, historical, hypothetical, or other-experiencer concepts return False.

Research-Data-Wrangling (rdw) example

result = df_codes.select(
    pl.col('code')
    .rdw.starts_with_any(['J12', 'J13', 'J14', 'J15'])
    .alias('respiratory'),
)

The .rdw helpers use literal string matching rather than regular expressions.

Documentation

Page Contents
Public API Compact index of the public Python API
Clinical NLP API .cnlp expressions, return values, and examples
Research Data Wrangling API .rdw expressions
Algorithms ConText, NegEx, contextual dimensions, and finding ranking
Custom rules Extend defaults, replace rule sets, scope, pseudo, and termination rules
Advanced usage Lazy queries, prefiltering, Struct outputs, null semantics, and validation
How it works High-level execution model and Rust-backed Polars plugin architecture