Insee Première - toutes les publications

Données - INSEE

Code
source(here::here("_rinit.R"))
invisible(Sys.setlocale("LC_TIME", "fr_FR.UTF-8"))
# cd ~/iCloud/website/data/insee; Rscript insee_premiere.R   # (re)télécharge le parquet
# cd ~/iCloud/website/data/insee; /usr/local/bin/R -e 'quarto::quarto_render("insee_premiere.qmd")'

knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE,
                      fig.width = 9, fig.height = 4.5, dpi = 150)

ip_path <- here::here("data", "insee", "insee_premiere.parquet")
ip <- arrow::read_parquet(ip_path) |>
  dplyr::arrange(dplyr::desc(date))

n_ip <- nrow(ip)
periode <- range(ip$date, na.rm = TRUE)

857 numéros d’Insee Première (collection « Insee Première » du site insee.fr), du 30 juin 2001 au 23 septembre 2026. Le tableau ci-dessous permet de chercher dans les titres, les résumés et les thèmes (champ de recherche en haut à gauche), de filtrer par colonne et de trier. Cliquer sur la flèche à gauche d’une ligne affiche le résumé (chapô) ; le numéro ouvre la publication sur insee.fr.

Recherche

Code
ip |>
  dplyr::transmute(
    Date = date,
    `N°` = sprintf('<a href="%s" target="_blank">%s</a>', url, numero),
    Titre = titre,
    Thème = theme,
    Résumé = chapo
  ) |>
  reactable::reactable(
    searchable = TRUE, filterable = TRUE, defaultPageSize = 25,
    showPageSizeOptions = TRUE, pageSizeOptions = c(10, 25, 50, 100),
    highlight = TRUE, striped = TRUE, compact = TRUE, wrap = TRUE,
    language = reactable::reactableLang(
      searchPlaceholder = "Rechercher un titre, un mot du résumé, un thème…",
      noData = "Aucun Insee Première trouvé",
      pageInfo = "{rowStart}–{rowEnd} sur {rows} numéros",
      pagePrevious = "Précédent", pageNext = "Suivant"
    ),
    columns = list(
      Date = reactable::colDef(format = reactable::colFormat(date = TRUE, locales = "fr-FR"),
                               minWidth = 90, filterable = FALSE),
      `N°` = reactable::colDef(html = TRUE, minWidth = 60),
      Titre = reactable::colDef(minWidth = 320),
      Thème = reactable::colDef(minWidth = 160),
      Résumé = reactable::colDef(show = FALSE)
    ),
    details = function(i) {
      htmltools::div(style = "padding: 8px 16px; color: #444;",
                     ip$chapo[i])
    },
    searchMethod = reactable::JS("function(rows, columnIds, searchValue) {
      var q = searchValue.toLowerCase().normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');
      var words = q.split(/\\s+/).filter(Boolean);
      return rows.filter(function(row) {
        var s = Object.values(row.values).join(' ').toLowerCase()
                  .normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');
        return words.every(function(w) { return s.indexOf(w) >= 0; });
      });
    }")
  )

La recherche est insensible à la casse et aux accents, et tous les mots saisis doivent être présents (dans le titre, le thème ou le numéro). Le résumé est inclus dans la recherche même s’il n’est affiché que dans le détail de la ligne.

Nombre de publications par an

Code
ip |>
  dplyr::count(annee = lubridate::year(date)) |>
  ggplot(aes(annee, n)) +
  geom_col(fill = "#2c6fbb") +
  scale_x_continuous(breaks = scales::pretty_breaks(12)) +
  labs(x = NULL, y = "Nombre d'Insee Première",
       title = "Insee Première publiés par an") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold"),
        panel.grid.minor = element_blank())

Par thème

Code
ip |>
  dplyr::count(Thème = theme, sort = TRUE) |>
  dplyr::left_join(
    ip |> dplyr::group_by(Thème = theme) |>
      dplyr::summarise(`Dernier` = max(date), .groups = "drop"),
    by = "Thème") |>
  dplyr::rename(`Nombre` = n) |>
  reactable::reactable(defaultPageSize = 15, compact = TRUE, striped = TRUE,
                       columns = list(Dernier = reactable::colDef(
                         format = reactable::colFormat(date = TRUE, locales = "fr-FR"))))

Publications sur les salaires

L’Insee publie un Insee Première par versant de la fonction publique (État, territoriale, hospitalière), en plus d’un pour le secteur privé. Cette séparation date de 2013–2015 environ : avant, seuls les agents de l’État (puis la territoriale) étaient traités. Les deux tibbles ci-dessous sont extraits des titres (regex), le versant étant déduit du titre.

Code
tab_salaires <- function(df) {
  df |>
    dplyr::transmute(
      Date = date,
      `N°` = sprintf('<a href="%s" target="_blank">%s</a>', url, numero),
      Titre = titre
    ) |>
    reactable::reactable(
      defaultPageSize = 15, compact = TRUE, striped = TRUE, highlight = TRUE,
      searchable = TRUE, wrap = TRUE,
      columns = list(
        Date = reactable::colDef(format = reactable::colFormat(date = TRUE, locales = "fr-FR"),
                                 minWidth = 90),
        `N°` = reactable::colDef(html = TRUE, minWidth = 60),
        Titre = reactable::colDef(minWidth = 400)
      )
    )
}

salaires_fp <- ip |>
  dplyr::filter(stringr::str_detect(
    titre, stringr::regex("salaires? .*(fonction publique|agents de l.État|agents de la fonction publique)|hautes rémunérations dans la fonction publique",
                          ignore_case = TRUE))) |>
  dplyr::mutate(versant = dplyr::case_when(
    stringr::str_detect(titre, "hospitali") ~ "Hospitalière",
    stringr::str_detect(titre, "territorial") ~ "Territoriale",
    stringr::str_detect(titre, "l.État|d.État|d.Etat|d.etat") ~ "État",
    TRUE ~ "Ensemble / autre"))

salaires_prive <- ip |>
  dplyr::filter(stringr::str_detect(
    titre, stringr::regex("salaires? .*secteur privé|salaires dans les entreprises en 2008",
                          ignore_case = TRUE)))

Fonction publique

Code
salaires_fp |>
  dplyr::mutate(titre = paste0(titre, " [", versant, "]")) |>
  tab_salaires()
Code
salaires_fp |>
  dplyr::count(annee = lubridate::year(date), versant) |>
  ggplot(aes(annee, n, fill = versant)) +
  geom_col() +
  scale_x_continuous(breaks = scales::pretty_breaks(12)) +
  labs(x = NULL, y = "Publications", fill = NULL,
       title = "Salaires dans la fonction publique : Insee Première par versant") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold"), legend.position = "bottom",
        panel.grid.minor = element_blank())

Secteur privé

Code
tab_salaires(salaires_prive)