Médecins libéraux par spécialité et lieu d’exécution (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("risque_medecins_specialites.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", "risque_medecins_specialites.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
m <- d |> filter(!est_total_general)
tot_gen <- d |> filter(est_total_general, lieu == "total", type_depense == "total")
hon <- m |> filter(mesure == "honoraires", lieu == "total", type_depense == "total") |> select(specialite, honoraires = valeur, evol_hon = evolution)
rbl <- m |> filter(mesure == "depenses_remboursables", lieu == "total", type_depense == "total") |> select(specialite, remboursable = valeur, evol_remb = evolution)
rbe <- m |> filter(mesure == "depenses_remboursees", lieu == "total", type_depense == "total") |> select(specialite, rembourse = valeur)
sp <- hon |> left_join(rbl, by = "specialite") |> left_join(rbe, by = "specialite") |>
  mutate(ecart = honoraires - remboursable, taux_ecart = ecart / honoraires, taux_amo = rembourse / honoraires)

Dépenses des médecins libéraux par spécialité et lieu d’exécution (cabinets libéraux, cliniques privées), cumul à fin juillet 2026, en euros : honoraires perçus, dépenses remboursables, dépenses remboursées, par type d’acte (actes cliniques, actes techniques, permanence des soins, rémunération du médecin traitant, participation forfaitaire, autres) et évolution PCAP. Pour l’ensemble des médecins libéraux : 19,7 Md€ d’honoraires, 16,7 Md€ de dépenses remboursables et 14,2 Md€ remboursées.

Les spécialités qui pèsent le plus

Code
sp |> slice_max(honoraires, n = 20) |> barh(specialite, honoraires) +
  labs(title = "Honoraires perçus par spécialité, cumul janv.-juil. 2026")

Honoraires versus dépenses remboursables : l’écart

Les honoraires perçus dépassent les dépenses remboursables (assises sur les tarifs opposables) du fait des dépassements d’honoraires (secteur 2) et des dépenses hors nomenclature.

Code
sp |> filter(honoraires > 2e8) |> barh(specialite, taux_ecart, fmt = pct, fill = col2) +
  labs(title = "Part des honoraires au-delà du remboursable, spécialités > 200 M€",
       subtitle = "(honoraires − dépenses remboursables) / honoraires")

Code
top4 <- sp |> filter(honoraires > 2e8) |> slice_max(taux_ecart, n = 4)
bas3 <- sp |> filter(honoraires > 2e8) |> slice_min(taux_ecart, n = 3)

L’écart est le plus important pour chirurgie (37,6%), gynécologie (35,4%), anesthésie-réanimation chirurgicale (33,5%), ophtalmologie (32,9%) ; il est le plus faible pour scanner-irm-tomographie-forfaits consommables (0,0%), médecine nucléaire (0,5%), radiothérapeutes (1,3%).

Cabinet ou clinique ?

Code
m |> filter(mesure == "depenses_remboursables", lieu %in% c("cabinets", "cliniques"), type_depense == "total") |>
  group_by(specialite) |> mutate(tot = sum(valeur)) |> ungroup() |> filter(tot > 1.5e8) |>
  mutate(specialite = forcats::fct_reorder(specialite, valeur * (lieu == "cliniques") / tot, sum)) |>
  ggplot(aes(specialite, valeur, fill = lieu)) + geom_col(position = "fill") + coord_flip() +
  scale_y_continuous(labels = scales::label_percent()) +
  scale_fill_manual(values = c(cabinets = col1, cliniques = col2)) +
  labs(x = NULL, y = NULL, fill = NULL, title = "Lieu d'exécution des dépenses remboursables (spécialités > 150 M€)") + theme_cnam

Actes cliniques ou techniques ?

Code
m |> filter(mesure == "depenses_remboursables", lieu == "total",
            type_depense %in% c("actes_cliniques", "actes_techniques", "autres", "permanence_des_soins", "remuneration_medecin_traitant")) |>
  group_by(specialite) |> mutate(tot = sum(valeur, na.rm = TRUE)) |> ungroup() |> filter(tot > 1.5e8) |>
  mutate(specialite = forcats::fct_reorder(specialite, valeur * (type_depense == "actes_techniques") / tot, sum, na.rm = TRUE)) |>
  ggplot(aes(specialite, valeur, fill = type_depense)) + geom_col(position = "fill") + coord_flip() +
  scale_y_continuous(labels = scales::label_percent()) + scale_fill_brewer(palette = "Set2") +
  labs(x = NULL, y = NULL, fill = NULL, title = "Nature des dépenses remboursables par spécialité") + theme_cnam

Dynamique

Code
sp |> filter(remboursable > 1.5e8) |>
  ggplot(aes(remboursable, evol_remb, label = specialite)) + geom_point(colour = col1, size = 2) +
  ggrepel::geom_text_repel(size = 3, max.overlaps = 20) +
  scale_x_log10(labels = mdd) + scale_y_continuous(labels = scales::label_percent()) +
  labs(x = "Dépenses remboursables (échelle log)", y = "Évolution PCAP", title = "Croissance et poids des spécialités") + theme_cnam

Source

Caisse nationale de l’Assurance Maladie (Cnam) — Cnam (SNDS) — Dépenses par type de risque, résultats cumulés à fin juillet 2026, onglet « Médecins spécialités ». Conversion Excel → Parquet : cnam.R (dossier data/cnam).