Biologie médicale 2026 — actes remboursés par groupe et taux de remboursement

Données - Assurance Maladie (Cnam)

Code
source(here::here("_rinit.R"))
invisible(Sys.setlocale("LC_TIME", "fr_FR.UTF-8"))
# cd ~/iCloud/website/data/cnam; /usr/local/bin/R -e 'quarto::quarto_render("biologie_2026.qmd")'
# (données : Rscript --vanilla cnam.R)

knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
                      fig.width = 9, fig.height = 5.5, dpi = 150)
library(dplyr); library(tidyr); library(ggplot2); library(stringr)

path <- here::here("data", "cnam", "biologie_2026.parquet")
d <- arrow::read_parquet(path)

mdd <- scales::label_number(scale = 1e-9, suffix = " Md€", accuracy = 0.1, big.mark = " ", decimal.mark = ",")
mde <- scales::label_number(scale = 1e-6, suffix = " M€", accuracy = 1, big.mark = " ", decimal.mark = ",")
pct <- scales::label_percent(accuracy = 0.1, decimal.mark = ",")
nb  <- scales::label_number(big.mark = " ", decimal.mark = ",")

theme_cnam <- theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 13), plot.title.position = "plot",
        plot.subtitle = element_text(colour = "grey35"),
        panel.grid.minor = element_blank(), legend.position = "bottom")
col1 <- "#1b7f79"; col2 <- "#c0392b"

# barres horizontales triées
barh <- function(df, lab, val, fmt = mdd, fill = col1, ...) {
  df |>
    mutate(.l = forcats::fct_reorder({{ lab }}, {{ val }})) |>
    ggplot(aes(.l, {{ val }})) +
    geom_col(fill = fill, ...) +
    geom_text(aes(label = fmt({{ val }})), hjust = -0.08, size = 3) +
    coord_flip() +
    scale_y_continuous(labels = fmt, expand = expansion(mult = c(0, 0.2))) +
    labs(x = NULL, y = NULL) + theme_cnam
}
Code
b <- d |> mutate(is100 = str_detect(taux_remboursement, "^100"),
                 grp = paste0(code_grp, " — ", str_to_sentence(str_trunc(libelle_grp, 45))))
mois_l <- sort(unique(b$mois))
par_mois <- b |> group_by(mois) |> summarise(m = sum(montant_rembourse, na.rm = TRUE), n = sum(nombre_actes, na.rm = TRUE),
                                             base = sum(base_remboursement, na.rm = TRUE), .groups = "drop")

Actes de biologie médicale remboursés par l’Assurance maladie (tous régimes, France entière, en date de remboursement), mois par mois de janvier à juin 2026, ventilés par acte (nomenclature NABM), groupe (GRP) et taux de remboursement (100 % ou non). Chaque ligne donne la base de remboursement, le nombre d’actes et le montant remboursé. Au total 925 actes et 30 groupes.

Volumes et dépenses par mois

Code
par_mois |> ggplot(aes(mois, m)) + geom_col(fill = col1, width = 20) +
  geom_text(aes(label = mde(m)), vjust = -0.4, size = 3.3) +
  scale_y_continuous(labels = mdd, expand = expansion(mult = c(0, .12))) +
  scale_x_date(date_labels = "%b %Y", breaks = mois_l) +
  labs(x = NULL, y = NULL, title = "Biologie : montant remboursé par mois") + theme_cnam

Sur la période, 1,9 Md€ ont été remboursés pour 588 millions d’actes, soit un remboursé moyen de 3,25 € par acte. Le nombre de jours ouvrés influe fortement sur le montant mensuel : juin est le mois le plus chargé (364 M€) et mai le plus léger (278 M€).

Par groupe d’actes

Code
b |> group_by(grp) |> summarise(m = sum(montant_rembourse, na.rm = TRUE)) |> slice_max(m, n = 20) |>
  barh(grp, m) + labs(title = "Montant remboursé par groupe (GRP), 20 premiers")

Code
b |> group_by(grp) |>
  summarise(Remboursé = sum(montant_rembourse, na.rm = TRUE), Actes = sum(nombre_actes, na.rm = TRUE),
            Base = sum(base_remboursement, na.rm = TRUE), .groups = "drop") |>
  mutate(`€ / acte` = Remboursé / Actes, `Taux effectif` = Remboursé / Base) |>
  arrange(desc(Remboursé)) |> slice_head(n = 15) |> select(-Base) |>
  gt::gt() |> gt::fmt_number(c(Remboursé, Actes), decimals = 0, sep_mark = " ") |>
  gt::fmt_number(`€ / acte`, decimals = 2) |> gt::fmt_percent(`Taux effectif`, decimals = 1) |>
  gt::tab_options(table.width = "100%")
grp Remboursé Actes € / acte Taux effectif
29 — Dispositions generales 256 952 286 134 122 880 1.92 78.9%
4 — Biochimie courante (en dehors des groupes) 173 399 484 88 790 520 1.95 78.5%
90 — Autres (tous les autres codes) 172 699 084 15 021 893 11.50 72.4%
1 — Hematologie courante 128 328 942 41 471 911 3.09 77.6%
17 — Microbiologie courante 123 336 893 8 980 438 13.73 71.7%
12 — Proteines seriques 101 891 541 34 294 632 2.97 78.1%
7 — Exploration hepatique 96 761 208 75 406 359 1.28 78.0%
19 — Hepatites virales 89 068 731 6 196 123 14.37 74.9%
9 — Exploration thyroidienne 88 262 946 19 597 402 4.50 71.7%
11 — Ionogrammes 66 303 951 33 226 336 2.00 80.8%
8 — Exploration cardiaque 65 590 866 10 420 057 6.29 87.2%
15 — Hormonologie courante 64 980 628 8 279 399 7.85 70.7%
10 — Fer - ferritine 59 202 596 18 873 191 3.14 73.3%
6 — Exploration glucidique 58 977 760 34 730 354 1.70 79.2%
5 — Exploration lipidique 58 641 079 20 388 453 2.88 73.4%

100 % ou non ?

Le champ taux_remboursement distingue les actes pris en charge à 100 % (ALD, maternité, exonérations…) de ceux qui ne le sont pas (ticket modérateur à la charge de l’assuré ou de sa complémentaire).

Code
b |> group_by(is100) |> summarise(m = sum(montant_rembourse, na.rm = TRUE), n = sum(nombre_actes, na.rm = TRUE), base = sum(base_remboursement, na.rm = TRUE)) |>
  mutate(lab = if_else(is100, "Remboursés à 100 %", "Non remboursés à 100 %"),
         part_m = m / sum(m), part_n = n / sum(n), taux = m / base) |>
  transmute(Catégorie = lab, `Montant remboursé` = m, `Part du remboursé` = part_m, `Part des actes` = part_n, `Taux effectif de remb.` = taux) |>
  gt::gt() |> gt::fmt_number(`Montant remboursé`, decimals = 0, sep_mark = " ") |>
  gt::fmt_percent(matches("^(Part|Taux)"), decimals = 1) |> gt::tab_options(table.width = "100%")
Catégorie Montant remboursé Part du remboursé Part des actes Taux effectif de remb.
Non remboursés à 100 % 862 848 928 45.2% 54.9% 59.7%
Remboursés à 100 % 1 047 787 641 54.8% 45.1% 100.0%
Code
b |> group_by(grp, is100) |> summarise(m = sum(montant_rembourse, na.rm = TRUE), .groups = "drop") |>
  group_by(grp) |> mutate(tot = sum(m), part100 = m[is100] / tot) |> ungroup() |>
  filter(tot > 4e7) |> distinct(grp, part100) |> barh(grp, part100, fmt = pct, fill = "#8e6cb8") +
  labs(title = "Part du remboursé passant par des actes à 100 %, groupes > 40 M€")

Les actes les plus dépensiers

Code
b |> group_by(acte, libelle_acte) |>
  summarise(Remboursé = sum(montant_rembourse, na.rm = TRUE), Actes = sum(nombre_actes, na.rm = TRUE), .groups = "drop") |>
  slice_max(Remboursé, n = 20) |> mutate(`€ / acte` = Remboursé / Actes, libelle_acte = str_trunc(libelle_acte, 70)) |>
  rename(Code = acte, Libellé = libelle_acte) |>
  gt::gt() |> gt::fmt_number(c(Remboursé, Actes), decimals = 0, sep_mark = " ") |> gt::fmt_number(`€ / acte`, decimals = 2) |>
  gt::tab_options(table.width = "100%")
Code Libellé Remboursé Actes € / acte
9005 FORFAIT DE PRISE EN CHARGE PRE-ANALYTIQUE DU PATIENT 193 978 956 60 813 331 3.19
1104 HEMOGRAMME Y COMPRIS PLAQUETTES (NFS , NFP) 118 663 468 35 921 622 3.30
1208 T.S.H.(SANG) 57 955 532 16 121 768 3.59
996 SANG : EXPLORATION D'UNE ANOMALIE LIPIDIQUE 56 621 705 19 198 021 2.95
5201 EX MICROBIO URINES (ECBU) 47 775 415 5 234 141 9.13
1609 SANG : IONOGRAMME (NA+K+ EVENTUELLEMENT CL) 47 764 830 26 960 306 1.77
1213 FERRITINE (DOSAGE) (SANG) 47 138 066 15 235 228 3.09
522 TRANSAMINASES (ALAT ET ASAT, TGP ET TGO)(SANG) 45 501 521 26 134 266 1.74
1821 PEPTIDES NATRIURETIQUES (ANP, BNP, NT-PROBNP) (DOSAGE) (SANG) 44 221 408 4 486 435 9.86
592 CREATININE (CREATININEMIE): 41 074 254 34 469 747 1.19
4500 HEPATITE B (VHB): DEPISTAGE ET/OU DIAGNOSTIC 38 401 017 2 288 309 16.78
9105 FORFAIT DE SECURITE POUR ECHANTILLON SANGUIN 35 400 101 58 795 119 0.60
1577 HBA1C (DOSAGE) (SANG) 28 998 872 10 333 555 2.81
1804 CRP (PROTEINE C REACTIVE) (DOSAGE) (SANG) 28 430 745 20 924 098 1.36
7318 ANTIGENE PROSTATIQUE SPECIFIQUE (PSA)-PSA TOTAL 27 429 931 4 812 512 5.70
1387 FOLATES SERIQUES OU ERYTHROCYTAIRES (DOSAGE) (SANG) 27 411 574 4 951 486 5.54
1374 VITAMINE B 12 (DOSAGE) (SANG) 26 366 402 4 749 235 5.55
3784 HEPATITE C (VHC) : SD DE DEPISTAGE : AC ANTI-VHC 24 425 728 2 274 280 10.74
388 INFECTION A VIH 1 ET 2 : SD DE DEPISTAGE 23 589 266 2 357 451 10.01
570 ELECTROPHORESE DES PROTEINES SERIQUES (PROTEINOGRAMME) 23 505 619 2 690 424 8.74

Source

Caisse nationale de l’Assurance Maladie (Cnam) — Cnam — Actes de biologie remboursés (tous régimes, en date de remboursement), série mensuelle 2026 par taux de remboursement. Conversion Excel → Parquet : cnam.R (dossier data/cnam).