Résultats détaillés — prestations par risque, montants et nombres (juillet 2026)

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("resultats_detail.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", "resultats_detail.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
x <- d
mois_ref <- unique(x$mois_ref)
cnt <- x |> count(risque, mesure, periode, name = "lignes")

Le détail de la statistique mensuelle de la Cnam : prestations par prestation (consultations, visites, actes techniques, forfaits, rémunérations…) pour cinq blocs — maladie, maternité, invalidité et décès, accidents du travail, tous risques — en montants (euros) et en nombres (actes), pour le mois de juillet 2026 et le cumul janvier-juillet. Pour la maladie, les montants sont ventilés avec / sans ticket modérateur (assurés exonérés : ALD, maternité, accidents du travail…), dont prestations en cliniques privées et conventions internationales, avec l’évolution (PCAP ou GAM). Format long : une ligne par prestation × colonne × risque × mesure × période (14 032 valeurs).

Code
cnt |> pivot_wider(names_from = periode, values_from = lignes) |>
  gt::gt() |> gt::tab_options(table.width = "60%")
risque mesure cumul mois
Accidents du travail montant 792 702
Accidents du travail nombre 274 233
Invalidité et décès montant 18 18
Maladie montant 1904 1831
Maladie nombre 570 564
Maternité montant 840 762
Maternité nombre 286 269
Tous risques montant 1957 1885
Tous risques nombre 565 562

Honoraires des médecins : montants et volumes

Code
mal <- x |> filter(risque == "Maladie", periode == "cumul", colonne == "total")
mnt <- mal |> filter(mesure == "montant", prestation %in% c("Consultations", "Visites (y compris frais de déplacement)"))
nbr <- mal |> filter(mesure == "nombre", prestation %in% c("Consultations", "Visites"))
Code
bind_rows(
  mnt |> filter(prestation == "Consultations") |> select(section, montant = valeur) |>
    inner_join(nbr |> filter(prestation == "Consultations") |> select(section, nombre = valeur), by = "section") |>
    mutate(acte = "Consultations"),
  mnt |> filter(str_starts(prestation, "Visites")) |> select(section, montant = valeur) |>
    inner_join(nbr |> filter(prestation == "Visites") |> select(section, nombre = valeur), by = "section") |>
    mutate(acte = "Visites")) |>
  filter(str_detect(section, "^(Omnipraticiens|Spécialistes)")) |>
  transmute(Section = section, Acte = acte, `Montant remboursé` = montant, `Nombre` = nombre, `Montant moyen (€)` = montant / nombre) |>
  gt::gt() |> gt::fmt_number(c(`Montant remboursé`, Nombre), decimals = 0, sep_mark = " ") |>
  gt::fmt_number(`Montant moyen (€)`, decimals = 2) |> gt::tab_options(table.width = "100%")
Section Acte Montant remboursé Nombre Montant moyen (€)
Omnipraticiens libéraux Consultations 3 015 137 187 119 323 869 25.27
Spécialistes libéraux Consultations 1 637 776 305 45 740 336 35.81
Omnipraticiens libéraux Visites 270 631 070 5 726 394 47.26

Rapporter le montant remboursé au nombre d’actes donne le montant moyen remboursé par consultation ou visite — nettement plus élevé chez les spécialistes que chez les omnipraticiens ; la visite à domicile est remboursée plus cher qu’une consultation (majorations de déplacement).

Les prestations les plus coûteuses (maladie, cumul)

Code
mal |> filter(mesure == "montant") |>
  group_by(section, prestation) |> summarise(v = sum(valeur), .groups = "drop") |>
  filter(!str_detect(prestation, "^(TOTAL|Total)")) |>
  slice_max(v, n = 25) |> mutate(l = paste0(prestation, "  [", str_trunc(section, 28), "]")) |>
  barh(l, v) + labs(title = "Assurance maladie : 25 prestations les plus coûteuses, janv.-juil. 2026")

Avec ou sans ticket modérateur ?

Code
x |> filter(risque == "Maladie", periode == "cumul", mesure == "montant",
            colonne %in% c("avec_ticket_moderateur", "sans_ticket_moderateur")) |>
  group_by(prestation, colonne) |> summarise(v = sum(valeur), .groups = "drop") |>
  group_by(prestation) |> mutate(tot = sum(v)) |> ungroup() |> filter(tot > 4e8) |>
  mutate(prestation = forcats::fct_reorder(str_trunc(prestation, 55), v * (colonne == "sans_ticket_moderateur") / tot, sum)) |>
  ggplot(aes(prestation, v, fill = colonne)) + geom_col(position = "fill") + coord_flip() +
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = c(avec_ticket_moderateur = col1, sans_ticket_moderateur = col2),
                    labels = c("Avec ticket modérateur", "Sans ticket modérateur (exonérés)")) +
  labs(x = NULL, y = NULL, fill = NULL, title = "Part des montants remboursés sans ticket modérateur, prestations > 400 M€") + theme_cnam

Autres risques : maternité, accidents du travail, invalidité

Code
x |> filter(risque == "Invalidité et décès", periode == "cumul", colonne == "total") |>
  select(Prestation = prestation, `Montant (€)` = valeur) |>
  gt::gt() |> gt::fmt_number(`Montant (€)`, decimals = 0, sep_mark = " ") |> gt::tab_options(table.width = "70%")
Prestation Montant (€)
Avantages de base - Assurés 4 643 424 901
Avantages de base 4 643 424 901
Allocations sup. - Assurés 165 514 707
Allocations supplémentaires 165 514 707
Majoration tierce personne - Assurés 91 720 719
Majoration tierce personnes 91 720 719
TOTAL PENSIONS SERVIES 4 900 660 327
TOTAL ASSURANCE INVALIDITE 4 900 660 327
TOTAL ASSURANCE DECES 66 562 838
Code
x |> filter(risque %in% c("Maternité", "Accidents du travail"), periode == "cumul", mesure == "montant", colonne == "total") |>
  filter(!str_detect(prestation, "^(TOTAL|Total)")) |>
  group_by(risque, prestation) |> summarise(v = sum(valeur), .groups = "drop") |>
  group_by(risque) |> slice_max(v, n = 10) |> ungroup() |>
  mutate(l = forcats::fct_reorder(paste0(str_trunc(prestation, 45), "___", risque), v)) |>
  ggplot(aes(l, v, fill = risque)) + geom_col(show.legend = FALSE) + coord_flip() +
  scale_x_discrete(labels = \(z) str_remove(z, "___.*")) + facet_wrap(~risque, scales = "free_y", ncol = 1) + scale_y_continuous(labels = mdd) +
  scale_fill_manual(values = c(col1, col2)) + labs(x = NULL, y = NULL, title = "Dix premières prestations, cumul janv.-juil.") + theme_cnam

Explorer

Code
x |> filter(periode == "cumul", risque == "Maladie", colonne %in% c("total", "evolution")) |>
  select(mesure, section_parent, section, prestation, colonne, valeur) |>
  pivot_wider(names_from = colonne, values_from = valeur, values_fn = sum) |>
  reactable::reactable(searchable = TRUE, filterable = TRUE, defaultPageSize = 15, compact = TRUE,
    columns = list(mesure = reactable::colDef(name = "Mesure", maxWidth = 90),
      section_parent = reactable::colDef(name = "Rubrique", minWidth = 160), section = reactable::colDef(name = "Sous-rubrique", minWidth = 160),
      prestation = reactable::colDef(name = "Prestation", minWidth = 220),
      total = reactable::colDef(name = "Total", format = reactable::colFormat(separators = TRUE, digits = 0)),
      evolution = reactable::colDef(name = "PCAP", format = reactable::colFormat(percent = TRUE, digits = 1))))

Source

Caisse nationale de l’Assurance Maladie (Cnam) — Cnam (SNDS) — « Résultats à fin juillet 2026 », onglets Maladie, Maternité, Invalidité, AT, Tous risques (montants et nombres, mois et cumul). Conversion Excel → Parquet : cnam.R (dossier data/cnam).