← Methods repository
CONCEPTFOUNDATIONALPYTHON · R5 citations

NCPDP Pharmacy Claim Fields

Pharmacy dispensing records transmitted under the NCPDP Telecommunication Standard (D.0) and adjudicated in real time at the point of sale by pharmacy benefit managers and commercial payers; each transaction carries an 11-digit NDC, quantity dispensed, days_supply, fill date, refill number, prescriber and pharmacy NPIs, a DAW (Dispense-as-Written) code, and cost-sharing amounts — the fields from which every adherence metric, generic-substitution analysis, and drug-utilization study in pharmacoepidemiology is constructed.

Data Standardcoding-systemdata-standardprimitiveclaimspharmacyncpdpdays-supplyndc
On this page
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.
In plain language

When a patient picks up a prescription at a pharmacy, the pharmacy instantly sends a digital transaction to the insurance company and receives approval in seconds — that real-time record is an NCPDP pharmacy claim, and it contains three fields that researchers rely on above all others: the drug's unique 11-digit code (NDC), the fill date, and the number of days the supply is meant to last (days_supply). Unlike hospital or doctor-visit claims that take weeks to process, pharmacy data land in the database the same day the prescription is filled, making them unusually clean and timely — but the days_supply field is entered by the pharmacist and can be wrong, especially for insulin and inhalers, so every adherence calculation built on it should be validated. One important gap: pharmacy claims cannot see drugs given in hospitals, free samples, or prescriptions paid with a discount card like GoodRx.

When to use it
Prefer NCPDP pharmacy claims for self-administered outpatient drug exposure and adherence measurement. Prefer institutional claims for inpatient drug administration, care-setting context, and for excluding inpatient...
Prefer pharmacy claims for self-administered medication adherence and utilization. Prefer professional claims for physician-administered drugs (J-codes) and prescriber-level attribution.
Watch out for
Pharmacy claims are blind to inpatient drug administration (bundled into DRG), cash/discount fills (GoodRx, $4 generics), physician-administered drugs (J-codes on medical claims), free samples, and OTC drugs;
Professional claims carry J-codes for physician-administered drugs that never appear in pharmacy claims; for drugs with infusion formulations, professional claims are the only claims-based data source and must be...

What NCPDP pharmacy claims are and why they differ from institutional and professional claims

Pharmacy claims are fundamentally different from the two claim types that anchor the rest of US administrative data — the UB-04/837I institutional claim and the CMS-1500/837P professional claim. The institutional and professional claims are submitted in batch after services are rendered and adjudicated days to weeks later.

A pharmacy claim is adjudicated in real time at the point of sale: the pharmacist's dispensing software sends the NCPDP transaction to the pharmacy benefit manager (PBM) or payer in seconds, receives an approval or rejection response before the patient leaves the counter, and the resulting paid claim lands in the insurer's data warehouse within hours. That real-time loop has a direct consequence for research: pharmacy claims data are substantially cleaner, more complete, and closer to the time of the service event than any other US administrative data source.

The clean data, however, carry their own failure modes — chiefly in the `days_supply` field — that are unique to the pharmacy transaction model and can silently corrupt every adherence measure downstream.

The NCPDP Telecommunication Standard (D.0) and the NCPDP SCRIPT Standard

The NCPDP D.0 (version D, implemented 2009 under HIPAA) is the transaction set that governs real-time pharmacy claim submission, adjudication, and response. Every retail, mail-order, and specialty pharmacy in the United States uses D.0 transactions for benefit claims. The NCPDP SCRIPT standard governs electronic prescribing (e-prescribing), routing new prescriptions and refill requests between prescribers and pharmacies; it is the upstream source of the prescriber NPI that appears on the dispensing claim.

Researchers encounter these transaction records as "pharmacy claims" in research databases (Medicare Part D Prescription Drug Events, commercial PBM extracts, Medicaid drug claims), but they originate from NCPDP D.0 transactions. Understanding this origin explains why pharmacy claims lack the institutional-claim complexity of interim bills, replacement claims, and TOB frequency codes — a dispensing event either happened or it did not, and reversals are their own transaction type.

Research-critical fields

NDC (11-digit, 5-4-2 HIPAA format): The National Drug Code identifying the exact drug product dispensed — labeler, product, and package. NDC is the primary key for all exposure code lists. A single drug and strength may span dozens or hundreds of NDCs across generic manufacturers and repackagers; a code list must be exhaustive or it silently undercounts exposure. NDC is covered in depth in its own catalog entry (see `ndc-national-drug-code`).

Quantity dispensed: The number of dosage units (tablets, capsules, milliliters) dispensed on this fill. Used with the NDC to confirm the supply is plausible: 30 tablets of a once-daily medication at a `days_supply` of 30 is consistent; 30 tablets at a `days_supply` of 90 signals a data-entry error or a three-tablet-per-day regimen. Quantity alone does not determine coverage duration; `days_supply` does.

days_supply: The number of days the dispensed quantity is intended to last. This is the single most consequential field in pharmacoepidemiology research — every adherence metric (PDC, MPR), every drug episode construction, and every index-date new-user window depends on it. It is also the field most prone to systematic measurement error, discussed in depth below.

Fill date (date_of_service / prescription_service_date): The date the prescription was dispensed. Fill date defines when a coverage interval begins and is the anchor for all longitudinal analyses. Because pharmacy claims are real-time, the fill date is generally trustworthy; the main exception is mail-order fills, where the dispensing date may precede actual patient receipt by several days.

Refill number / new-versus-refill flag: The fill number within an authorization sequence (0 = new prescription, 1 = first refill, etc.) or a binary new/refill indicator. This field is used in new-user design implementation to confirm the index fill is truly new (refill number = 0) rather than a continuation. In databases where refill number is unavailable, an incident new-user definition requires a washout period with no fills of the drug class to approximate the first fill.

Prescriber NPI: The National Provider Identifier of the clinician who wrote the prescription. Used to attribute dispensing events to a prescriber, link to specialty and practice characteristics, and study prescribing patterns. Completeness is generally high for Part D and commercial data, but data-entry of NPI at the pharmacy counter is imperfect, and some older records carry outdated or zeroed-out NPIs.

Pharmacy NPI / pharmacy identifier: The NPI of the dispensing pharmacy, supplemented by NCPDP provider number and chain store codes. Used in mail-order vs retail channel analyses, specialty pharmacy attribution, and geographic access studies. Mail-order pharmacies (high `days_supply`, NCPDP chain = mail) vs retail pharmacies (typical 30-day `days_supply`) behave differently for adherence and refill pattern studies, and pooling them without stratification distorts PDC estimates.

DAW code (Dispense-as-Written): A one-digit code transmitted by the pharmacy indicating the brand/generic substitution status of the fill: 0 = no product selection indicated (substitution permitted, generic dispensed); 1 = substitution not allowed by prescriber (brand required per prescriber's written DAW); 2 = substitution allowed — patient requested brand; 3–9 = other scenarios (substitution allowed — pharmacist selected product, substitution not allowed — regulatory required brand, etc.).

DAW code is the primary field for generic-substitution studies: an exposure algorithm that counts all fills regardless of DAW cannot distinguish prescriber-mandated brand use (DAW = 1) from voluntary brand use (DAW = 2) from generic filling (DAW = 0). In comparative effectiveness research where the treatment contrast is brand vs generic, misclassifying DAW codes is a direct form of exposure misclassification.

Copay / plan-paid amounts: The patient copay (cost-sharing), total ingredient cost, dispensing fee, and plan-paid amount are all present in adjudicated pharmacy claim records. These fields support cost-sharing and access analyses, out-of-pocket burden studies, and cost-effectiveness inputs. A critical limitation: the ingredient cost on the claim is the PBM's adjudicated allowed amount, not the manufacturer's list price and not the actual rebate-adjusted net price paid by the payer; studies of drug cost should be clear about which cost concept they are measuring.

Transaction type / service type code: Identifies whether the record is a paid claim, a reversal (B2 or transaction type 21), or a credit — see Reversal Transactions below.

days_supply: the most consequential field and its measurement error

`days_supply` is entered by the pharmacist or dispensing system at the time of fill and is subject to systematic data-entry patterns that produce bias in adherence metrics:

28 vs 30 day conventions: Some pharmacies dispense 28-day supplies rather than 30-day supplies, particularly for medications with weekly dosing (e.g., weekly bisphosphonates dispensed as 4-week blister packs = `days_supply` 28). In a 90-day window, a patient with three 28-day fills covers only 84 days, yielding PDC = 84/90 = 0.933 vs PDC = 90/90 = 1.0 for three 30-day fills. Stratifying by `days_supply` or using the actual pharmacy channel (mail, retail) and dosing schedule before pooling avoids conflating these conventions.

Insulin dosing and variable supply estimation: Insulin is dispensed in units (a vial of 10 mL of U-100 insulin contains 1,000 units), but the `days_supply` depends on the patient's individual daily dose, which varies by body weight, insulin resistance, and titration and is not directly recorded in the claim. Pharmacies estimate `days_supply` from the prescribed dose, the dispensed quantity, and standard dosing assumptions.

These estimates are notoriously unreliable: a patient who uses 50 units/day will deplete a 10 mL vial in 20 days, but if the pharmacy defaults to a standard 30-day supply estimation, the claim records `days_supply` = 30, overstating actual coverage. Studies of insulin adherence using PDC should validate `days_supply` distributions against clinical expectations and consider sensitivity analyses with alternative assumptions.

Inhaler supply and dose-counting: Similarly, inhaler `days_supply` depends on the number of puffs per day and the canister's rated dose count, neither of which is standardized in the claim. A rescue (short-acting) inhaler used PRN cannot have a meaningful `days_supply` — the claim field is meaningless for adherence purposes. Controller (maintenance) inhalers have a more predictable dosing pattern, but `days_supply` still requires validation against clinical dosing conventions for the specific product.

Reversal transactions (transaction type B2)

When a previously paid pharmacy claim is voided — because the patient returned the medication, the claim was submitted in error, or the adjudication is being corrected — the pharmacy submits a reversal transaction (identified in NCPDP D.0 by transaction type B2, or in claim files by a transaction type / claim status code indicating void or reversal). A reversal does not physically cancel the original record in most research databases; instead, both the original paid claim and the reversal record appear as separate rows.

An analyst who does not remove paired reversal records will count a drug fill that was ultimately never dispensed and retained by the patient. The clean approach is to identify claim pairs (same patient, same NDC, same fill date, same pharmacy) where a reversal matches the original, and drop both. In some data products, reversals are pre-processed and only net paid claims are delivered; always verify the vendor's data dictionary to determine whether reversals are present in the extract and require analyst-level removal.

Compound drug flags

Compounded prescriptions — custom drug preparations mixed by the pharmacy rather than manufactured by a labeler — appear in pharmacy claims with NDC codes that are not registered in the FDA NDC Directory. Some data systems flag these with a compound drug indicator or a specific service type code. Compounded drugs are common in some specialty areas (pediatrics, pain management, dermatology) and should be identified and handled separately from manufactured drugs in exposure code lists, as their NDC codes carry no standard product attributes.

What pharmacy claims do NOT capture — and the exposure-misclassification consequences

  • Inpatient hospital drugs: Medications administered during a hospital admission are part of the facility service, paid under the DRG or per-diem rate, and appear on the UB-04 institutional claim — not in pharmacy claims. A patient hospitalized for 5 days who is taking a maintenance medication will show a gap in pharmacy claims during those 5 days even if they received the drug in-hospital. Failure to account for inpatient periods in adherence denominators (PDC or MPR) makes these patients appear falsely non-adherent. The standard correction is to exclude inpatient days from both the numerator and denominator of PDC during hospitalization spans identified from institutional claims.
  • Cash-paid fills and discount-card fills (GoodRx, other discount programs): Prescriptions paid entirely out-of-pocket — whether at the true cash price or through a third-party discount card such as GoodRx — do not generate an insurance claim and are therefore completely invisible in claims databases. For commonly prescribed generic drugs that are available for $4 or less at many retail pharmacies, a material fraction of fills may be paid cash. This produces systematic underestimation of adherence and distorts new-user definitions: a patient may have been taking the drug for months via cash fills before appearing in claims as a "new user." The magnitude of this leakage varies dramatically by drug, formulary tier, and patient demographics, and cannot be corrected without external data.
  • Physician samples: Drug samples distributed by pharmaceutical representatives at the prescriber office do not generate a pharmacy claim. In therapeutic areas where aggressive sampling is common (some branded oral agents, some inhalers), the sample period can extend weeks to months before the patient converts to a filled prescription. New-user designs that anchor the index date at the first claim fill may misclassify the true initiation date by the length of the sample period.
  • Over-the-counter (OTC) drugs: Medications sold without a prescription — including many antihistamines, analgesics, proton pump inhibitors, and some statins in certain formulations — are not covered by pharmacy benefits and do not appear in claims. For conditions treated with both Rx and OTC products (e.g., heartburn with omeprazole), adherence measured from pharmacy claims captures only the prescription component.

Medical benefit vs pharmacy benefit drugs

A research-critical distinction: not all drugs in clinical use flow through pharmacy claims. Infused biologics (e.g., infliximab for rheumatoid arthritis, bevacizumab for cancer, vedolizumab for IBD) are typically administered in an infusion center or physician's office and billed as a physician-administered drug on the medical benefit — appearing as a HCPCS Level II J-code on the UB-04 institutional claim or CMS-1500 professional claim, not as an NDC on a pharmacy claim.

A study of biologic adherence that uses only pharmacy claims will miss every infusion visit for infused biologics, severely underestimating exposure. Researchers must query both the pharmacy benefit (NDC-based fills from NCPDP claims) and the medical benefit (J-code lines from institutional and professional claims) to capture the full utilization of drugs with both oral and infused formulations. Some specialty drugs are available in both a self-administered subcutaneous form (pharmacy benefit, NDC) and an infused form (medical benefit, J-code), requiring separate capture of each channel.

Pros, cons, and trade-offs — specific and comparative

  • vs UB-04 / 837I institutional claims: Pharmacy claims capture every retail and mail-order dispensing event with high completeness; institutional claims capture inpatient drug administration but not outpatient dispensing. The two are complementary, not redundant: a complete drug-exposure algorithm for a treatment that is sometimes infused (biologic) and sometimes oral (small molecule) must combine NCPDP pharmacy claims with institutional/professional claim J-code lines. For purely self-administered oral medications, pharmacy claims are the primary and often sole data source.
  • vs CMS-1500 / 837P professional claims: Professional claims carry J-codes for physician-administered drugs (e.g., subcutaneous injections administered in office) with line-level NDC on drug lines; pharmacy claims carry the full dispensed NDC for patient-self-administered drugs. For drugs administered in office vs self-administered, the two claim types are necessary complements. Professional claims do not carry `days_supply` or refill information, making adherence computation impossible from professional claims alone.
  • vs EHR prescribing records: EHR prescription orders capture the prescribing intent but not the fill — primary non-adherence (never picking up the prescription) is completely invisible in EHR order data. Pharmacy claims capture the actual dispensing event. PDC from prescribing data systematically overstates true coverage. When EHR and pharmacy claims are linked, the gap between the order date and first fill date quantifies primary non-adherence.
  • Real-time adjudication as a data quality advantage: Because pharmacy claims are adjudicated in real time at the point of sale, they contain essentially no administrative lag — the fill date in the claim is the actual dispensing date, and paid claims reflect current benefit enrollment. This is in sharp contrast to institutional claims, where the from/through dates in the adjudicated record may lag the service dates by weeks and where run-out periods of 60–90 days are needed before utilization data are considered complete.

When NOT to use — and when pharmacy claims are actively misleading or dangerous

  • For inpatient drug exposure: Drugs administered during hospital stays appear on UB-04 revenue code lines (revenue code 0250 for pharmacy, specific drug NDC on drug lines) or are bundled into the DRG payment with no line-level detail. Pharmacy claims show a gap during inpatient periods; using raw pharmacy claims without excluding inpatient days from the denominator produces false non-adherence in hospitalized patients. For any drug used in both inpatient and outpatient settings, query both data sources.
  • For infused biologics and J-coded drugs as the sole data source: A pharmacy-claims-only analysis of a drug class that includes both oral self-administered forms and infused forms (e.g., oral vs infused TNF inhibitors) will miss every infused fill, producing a biased and incomplete exposure classification. Always pair pharmacy claims with J-code lines from institutional and professional claims for drugs with infusion formulations.
  • For adherence measurement in the absence of continuous pharmacy benefit enrollment: A pharmacy claim is observable only if the patient has an active pharmacy benefit on the fill date. If a patient's pharmacy benefit lapses for one month and then restarts, the month of no claims looks identical to a month of non-adherence. PDC denominator windows must be restricted to periods of continuous pharmacy enrollment, not just medical benefit enrollment. Failure to verify pharmacy benefit enrollment generates false non-adherence in gap periods.
  • For drugs with unreliable `days_supply` estimation (insulin, inhalers, PRN medications): Adherence metrics that rely on `days_supply` are unreliable for these drug classes without additional validation of the field's clinical plausibility. A sensitivity analysis using alternative `days_supply` assumptions (e.g., computing expected days from quantity dispensed and standard dosing information from the label) should accompany any adherence analysis for variable-dose drugs.
  • As evidence of drug use during periods outside the claims database's pharmacy benefit capture: Patients enrolled in Medicare Advantage (MA) plans generate encounter data rather than FFS pharmacy claims for some data products. MA pharmacy claims may be systematically incomplete in some databases. Do not score MA-only members' prescription coverage from pharmacy claims without verifying that the data product includes full MA Part D PDE records.

Interpreting the output

The characteristic artifact of an NCPDP pharmacy claims analysis is a patient-level PDC score computed from fill dates and `days_supply` values. Taking the worked example below, the output is PDC = 85/90 ≈ 0.944 over a 90-day window.

Formal interpretation: A PDC of 85/90 = 0.944 means that in 85 of the 90 calendar days in the observation window, this patient had metformin supply on hand based on dispensing dates and pharmacy-reported `days_supply` values. PDC is a descriptive measure of observed fill-pattern coverage, not a causal estimand; it is bounded in [0, 1] and summarizes cumulative day-level coverage without reference to the patient's actual pill-taking behavior.

The 5-day uncovered gap (March 2–6) is observable from the raw fill records; whether it represents delayed refill, travel, or a coverage decision is not recoverable from the claim alone.

Practical interpretation: This patient is adherent by the conventional PDC ≥ 0.80 threshold. The 5-day gap early in March is a small deviation from perfect coverage. For a clinical decision or quality-measure context, this patient would be counted in the adherent numerator. For a comparative effectiveness analysis, caution is warranted: PDC 0.944 is a single scalar that erases the timing and pattern of the gap — a patient with the same PDC from six scattered 1-day gaps has the same score but a different exposure trajectory.

When the timing of non-adherence matters (e.g., adherence in the first 90 days vs second 90 days post-discharge), report coverage windows, not just the summary PDC.

Worked example

Scenario

An outcomes analyst is measuring metformin adherence for a newly diagnosed type 2 diabetes patient (person_id 5501) over the first 90 days after their prescription start date of 2023-01-01. The analyst pulls all paid NCPDP pharmacy claims for metformin (NDC 00093-5080-05, metformin HCl 500 mg tablets) for this patient, after first removing any reversal transactions. Three fills appear. The analyst needs to compute the proportion of days covered (PDC) using the union rule — counting each calendar day once regardless of overlap — and identify the gap in coverage.

Dataset

Three paid NCPDP pharmacy claims for patient 5501 (reversals pre-removed). NDC normalized to 11-digit HIPAA format. The 90-day observation window is 2023-01-01 through 2023-03-31.

person_idfill_datendc11drug_namedays_supplyquantity_dispenseddaw_codeplan_paid_amtrefill_number
55012023-01-0100093508005metformin HCl 500 mg3060012.40
55012023-01-3100093508005metformin HCl 500 mg3060012.41
55012023-03-0700093508005metformin HCl 500 mg3060012.42
FIG. 1 — DESIGN TIMELINE
NCPDP pharmacy fills for patient 5501: metformin days_supply coverage in 90-day window
NCPDP pharmacy fills for patient 5501: metformin days_supply coverage in 90-day window

Steps

1Confirm index fill: refill_number = 0 on the 2023-01-01 fill, confirming this is a new prescription. The 90-day observation window runs from 2023-01-01 through 2023-03-31 (January has 31 days, February has 28 days, March has 31 days; 31 + 28 + 31 = 90 days).
2Fill A (2023-01-01, days_supply 30): coverage spans 2023-01-01 through 2023-01-30 (last covered day = fill_date + days_supply - 1 = Jan 1 + 29 days = Jan 30). Days covered within window = 30.
3Fill B (2023-01-31, days_supply 30): immediately follows Fill A with no gap. Coverage spans 2023-01-31 through 2023-03-01. Days covered within window = 30. Fills A and B together form one contiguous block of 30 + 30 = 60 covered days (Jan 1 through Mar 1).
4Gap: 2023-03-02 through 2023-03-06 — five days with no supply on hand. Fill B's last covered day is Mar 1; Fill C does not begin until Mar 7. Gap length = 5 days.
5Fill C (2023-03-07, days_supply 30): coverage would extend to 2023-04-05, but the observation window closes 2023-03-31. Days covered within window = 31 - 7 + 1 = 25 (Mar 7 through Mar 31, inclusive).
6Total unique covered days in the 90-day window = 30 + 30 + 25 = 85. Gap days not covered = 5.
7DAW code = 0 on all three fills, confirming generic metformin was dispensed without any prescriber or patient brand mandate. Total plan-paid across three fills = 12.40 + 12.40 + 12.40 = 37.20 dollars.

Result

PDC = 85 / 90 ≈ 0.944. This patient is classified as adherent (PDC exceeds the 0.80 conventional threshold). The 5-day gap in early March (Mar 2–6) is observable from the fill record and represents a late refill rather than treatment discontinuation, since Fill C arrives 6 days after Fill B's supply runs out. The plan paid 12.40 + 12.40 + 12.40 = 37.20 dollars for three fills; zero patient copay (typical for a Tier 1 generic).

Trade-offs

Pros of this
Pharmacy claims are real-time adjudicated and complete for outpatient self-administered prescriptions; days_supply enables coverage-interval construction for adherence metrics; fills are patient-retained (no institutional administration confusion); data typically lack the interim-bill and replacement-claim complexity of institutional claims.
Pros of this
Pharmacy claims carry days_supply and refill number — fields absent from professional claims — enabling adherence metric computation and incident fill identification. NDC on pharmacy claims is the dispensed product NDC, not a billed J-code; it is more granular for drug-level analyses.

Runnable example

Core pharmacy claims operations: (1) load NCPDP claim records, remove reversal transactions, and validate days_supply; (2) compute PDC using the union rule for a fixed observation window with inpatient exclusion; (3) extract DAW code summary for generic substitution analysis.

requires: pandas · numpy
import pandas as pd
import numpy as np
from datetime import timedelta

# ---------------------------------------------------------------------------
# 1. REVERSAL REMOVAL
#    Remove paid-claim / B2-reversal pairs from the raw pharmacy claims extract.
#    Reversal records are identified by transaction_type == 'B2' or by negative
#    plan_paid_amt, depending on the data vendor's encoding.
# ---------------------------------------------------------------------------

def remove_reversals(df: pd.DataFrame) -> pd.DataFrame:
    """
    Remove reversal transactions and their corresponding original paid claims.

    Strategy:
      - If transaction_type column is present: mark B2 records and their pair
      - If absent: flag rows with negative plan_paid_amt (vendor-specific encoding)
    Returns only net paid claims.
    """
    df = df.copy()
    if "transaction_type" in df.columns:
        # Drop reversal records and their originals
        reversal_keys = df.loc[df["transaction_type"] == "B2",
                               ["person_id", "fill_date", "ndc11"]].drop_duplicates()
        df = df.merge(reversal_keys, on=["person_id", "fill_date", "ndc11"],
                      how="left", indicator=True)
        # Remove both the reversal AND any original with same person/date/ndc
        df = df[df["_merge"] == "left_only"].drop(columns=["_merge"])
        df = df[df["transaction_type"] != "B2"]
    else:
        # Fallback: negative plan_paid_amt indicates a reversal in some encodings
        df = df[df.get("plan_paid_amt", pd.Series([0] * len(df))) >= 0]
    return df.reset_index(drop=True)


# ---------------------------------------------------------------------------
# 2. PDC COMPUTATION (union rule, fixed window, with optional inpatient exclusion)
# ---------------------------------------------------------------------------

def compute_pdc(
    claims: pd.DataFrame,
    window_start: str,
    window_end: str,
    inpatient_spans: list[tuple[str, str]] | None = None,
) -> dict:
    """
    Compute PDC for one patient's pharmacy claims over a fixed observation window.

    Parameters
    ----------
    claims : DataFrame with fill_date (str/date) and days_supply (int) columns.
    window_start, window_end : ISO date strings defining the denominator window.
    inpatient_spans : list of (admission_date, discharge_date) str tuples to
        exclude from both numerator and denominator.

    Returns dict with covered_days, window_days, pdc, gap_days.
    """
    w_start = pd.Timestamp(window_start)
    w_end   = pd.Timestamp(window_end)
    window_days = (w_end - w_start).days + 1   # inclusive

    # Build a boolean array: one entry per calendar day in the window
    coverage = np.zeros(window_days, dtype=bool)
    inpatient_mask = np.zeros(window_days, dtype=bool)

    claims = claims.copy()
    claims["fill_date"] = pd.to_datetime(claims["fill_date"])

    for _, row in claims.iterrows():
        start_idx = max(0, (row["fill_date"] - w_start).days)
        end_idx   = min(window_days, start_idx + int(row["days_supply"]))
        if start_idx < window_days:
            coverage[start_idx:end_idx] = True

    # Mark inpatient days (exclude from numerator + denominator)
    if inpatient_spans:
        for adm, dis in inpatient_spans:
            adm_ts = pd.Timestamp(adm); dis_ts = pd.Timestamp(dis)
            s = max(0, (adm_ts - w_start).days)
            e = min(window_days, (dis_ts - w_start).days + 1)
            if s < window_days:
                inpatient_mask[s:e] = True

    active = ~inpatient_mask   # days eligible for PDC counting
    covered_days = int(coverage[active].sum())
    eligible_days = int(active.sum())
    pdc = covered_days / eligible_days if eligible_days > 0 else None
    gap_days = eligible_days - covered_days

    return {
        "covered_days":  covered_days,
        "window_days":   eligible_days,
        "pdc":           round(pdc, 4) if pdc is not None else None,
        "gap_days":      gap_days,
    }


# ---------------------------------------------------------------------------
# 3. DAW CODE SUMMARY (generic substitution analysis)
# ---------------------------------------------------------------------------

def daw_summary(df: pd.DataFrame) -> pd.DataFrame:
    """
    Summarize DAW code distribution across pharmacy claims.
    DAW 0 = generic dispensed as allowed
    DAW 1 = brand required by prescriber
    DAW 2 = brand requested by patient
    Returns a DataFrame with fill counts and percentage by DAW code.
    """
    daw_labels = {
        0: "Generic dispensed (substitution allowed)",
        1: "Brand required by prescriber",
        2: "Brand requested by patient",
        3: "Substitution allowed - pharmacist selected product",
        4: "Substitution not allowed - generic not in stock",
        5: "Substitution allowed - brand dispensed as generic",
        7: "Substitution not allowed - regulatory required",
        9: "Other",
    }
    counts = df["daw_code"].value_counts().rename("fill_count").reset_index()
    counts.columns = ["daw_code", "fill_count"]
    counts["description"] = counts["daw_code"].map(daw_labels).fillna("Unknown")
    counts["pct"] = (counts["fill_count"] / counts["fill_count"].sum() * 100).round(1)
    return counts.sort_values("daw_code")


# ---------------------------------------------------------------------------
# WORKED EXAMPLE (reproduces patient 5501 from the catalog entry)
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    raw_claims = pd.DataFrame({
        "person_id":    [5501, 5501, 5501],
        "fill_date":    ["2023-01-01", "2023-01-31", "2023-03-07"],
        "ndc11":        ["00093508005"] * 3,
        "drug_name":    ["metformin HCl 500 mg"] * 3,
        "days_supply":  [30, 30, 30],
        "quantity_dispensed": [60, 60, 60],
        "daw_code":     [0, 0, 0],
        "plan_paid_amt":[12.40, 12.40, 12.40],
        "refill_number":[0, 1, 2],
        # No transaction_type column -> reversal fallback to plan_paid_amt check
    })

    net_claims = remove_reversals(raw_claims)
    print(f"Net paid claims after reversal check: {len(net_claims)}")

    result = compute_pdc(net_claims, "2023-01-01", "2023-03-31")
    print(f"\nPDC result for patient 5501:")
    print(f"  Covered days : {result['covered_days']}")   # expected: 85
    print(f"  Window days  : {result['window_days']}")    # expected: 90
    print(f"  PDC          : {result['pdc']}")            # expected: 0.9444
    print(f"  Gap days     : {result['gap_days']}")       # expected: 5

    daw = daw_summary(net_claims)
    print(f"\nDAW code distribution:")
    print(daw.to_string(index=False))

Citations

FOUNDATIONAL / METHODS
  1. [1]Schneeweiss S, Avorn J. A review of uses of health care utilization databases for epidemiologic research on therapeutics. Journal of Clinical Epidemiology. 2005;58(4):323-337.
  2. [2]Burden AM, Paterson JM, Gruneir A, Cadarette SM. Adherence to osteoporosis pharmacotherapy is underestimated using days supply values in electronic pharmacy claims data. Pharmacoepidemiology and Drug Safety. 2015;24(5):537-543.
APPLIED EXAMPLES
  1. [3]Centers for Medicare & Medicaid Services. Medicare Prescription Drug Benefit Manual, Chapter 14: Coordination of Benefits. Baltimore, MD: CMS. Available from the CMS Prescription Drug Benefit Manual page.
REPORTING & GUIDANCE
  1. [4]National Council for Prescription Drug Programs (NCPDP). NCPDP Telecommunication Standard Implementation Guide, Version D.0. Scottsdale, AZ: NCPDP. Available at: https://standards.ncpdp.org/access-to-standards.aspx.
  2. [5]Research Data Assistance Center (ResDAC). Medicare Part D Prescription Drug Event (PDE) Data. Centers for Medicare & Medicaid Services. Minneapolis, MN: ResDAC; accessed 2024.