Tous les guides

Looker santé : réadmissions, durée de séjour, données patients

OMOP en bref, réadmission à 30 jours et durée de séjour définies une fois dans dbt, prévalence par concepts, champs patients protégés dans Looker. Dépôt public.

Yousri Majani, fondateur de Neuravoid · 9 min de lecture · Mis à jour le 6 septembre 2026

Un tableau de bord de pilotage hospitalier repose sur une poignée d'indicateurs dont chacun cache des choix de définition : quel séjour est un séjour index, à partir de quel jour une réadmission compte, ce qu'est une nuit. Sur un entrepôt au format OMOP dans BigQuery, la méthode qui tient consiste à fixer ces choix une fois dans dbt, à les tester à chaque construction, et à ne laisser Looker exposer que des comptes et des ratios de totaux, derrière des droits posés au niveau du modèle. Nous avons publié un dépôt de référence complet sur un jeu de données OMOP synthétique et public pour en montrer la mécanique.

OMOP en deux paragraphes

Le modèle commun de données OMOP (Observational Medical Outcomes Partnership) est un standard ouvert maintenu par la communauté OHDSI pour donner la même structure aux données de soins quelle que soit leur origine. Toutes les tables d'événements cliniques sont reliées à la table person : visit_occurrence pour les séjours et consultations, condition_occurrence pour les diagnostics, drug_exposure pour les médicaments, death, observation_period pour la fenêtre pendant laquelle les données d'un patient sont fiables. La version courante est la 5.5.

La seconde moitié du modèle est son vocabulaire standardisé. Chaque code source (un code CIM-9 ou CIM-10, par exemple) est conservé tel quel et rattaché à un concept standard, le plus souvent SNOMED pour les diagnostics, via la table concept. La table concept_ancestor donne la fermeture transitive de la hiérarchie : tous les descendants de « diabète sucré » en une jointure. Pour la BI, deux conséquences : un même modèle dbt sert plusieurs établissements, et une cohorte se définit par un identifiant de concept plutôt que par une recherche de chaîne de caractères.

Réadmission à 30 jours : les choix qui changent le chiffre

Le taux de réadmission est une famille de chiffres, et chaque choix ci-dessous le déplace de plusieurs points.

Choix Option du dépôt de référence Alternative courante Effet
Fenêtre Jour 1 à jour 30 après la sortie, le jour 0 étant un transfert Jour 0 inclus Hausse
Cause Toutes causes Réadmissions non planifiées, par algorithme Baisse
Séjour index Hospitalisation avec date de sortie, patient vivant à la sortie, au moins 30 jours de données après la sortie Sans censure des 30 derniers jours Le dernier mois paraît artificiellement bas
Établissement Tout le réseau Même établissement Baisse
Concept 262 (urgences puis hospitalisation) Un seul séjour hospitalier Deux séjours Double comptage

La mesure de référence des CMS aux États-Unis, la réadmission toutes causes non planifiée à 30 jours, exclut du numérateur les réadmissions planifiées à l'aide d'un algorithme qui classe certains soins comme toujours planifiés (accouchement, greffe, chimiothérapie d'entretien, rééducation) et n'admet jamais comme planifiée une admission pour maladie aiguë ou complication. Le dépôt de référence applique une version simplifiée, toutes causes, et l'écrit noir sur blanc dans le glossaire. La fenêtre et les listes de concepts de visite sont des variables dbt : une définition locale plus stricte est un changement de configuration suivi d'un test, pas une réécriture.

La mécanique compte autant que le choix. Le modèle int_readmissions ordonne les séjours hospitaliers de chaque patient et utilise LEAD et LAG pour trouver l'admission suivante et la sortie précédente. Deux drapeaux atterrissent sur fct_encounters au grain du séjour, is_index_admission et is_readmitted_within_30d, et un test dbt vérifie à chaque construction que le second n'est jamais vrai quand le premier est faux. Dans Looker, le taux devient un ratio de deux comptes filtrés, qui se découpe par date, établissement, praticien ou tranche d'âge sans seconde requête et se détaille jusqu'aux séjours qui le composent.

Durée de séjour : des nuits, un ratio de totaux

La durée moyenne de séjour est le total des nuits entre admission et sortie divisé par le nombre de sorties d'hospitalisation. Des nuits, pas des jours : une sortie le jour même vaut zéro. Et un ratio de totaux, jamais une moyenne des moyennes par établissement, faute de quoi le petit service qui garde ses patients longtemps pèse autant que le grand.

measure: average_length_of_stay {
  label: "Durée moyenne de séjour"
  description: "M4. Total des nuits divisé par les sorties d'hospitalisation. Ratio de totaux."
  type: number
  sql: ${total_nights} / NULLIF(${inpatient_discharge_count}, 0) ;;
  value_format: "0.0"
}

Prévalence chronique par hiérarchie de concepts

La prévalence du diabète, de l'hypertension, de la BPCO ou de l'insuffisance cardiaque se définit par un concept SNOMED parent (201820, 316866, 255573, 316139) étendu à tous ses descendants via concept_ancestor. Pas de LIKE '%diabet%', pas de liste de codes CIM tapée à la main : la définition survit aux mises à jour du vocabulaire, s'audite comme un seul identifiant, et ajouter un cinquième groupe est une ligne dans dbt_project.yml.

Le dénominateur est la file active, les patients ayant au moins un séjour, et non l'ensemble des personnes : une personne sans contact avec le système de soins n'a aucune occasion d'être diagnostiquée dans les données. Les codes source sans correspondance standard atterrissent sur le concept 0, libellé « aucun concept correspondant » et conservé plutôt que supprimé, pour que le total des diagnostics reste réconciliable avec la source.

Protéger les champs patients dans Looker

Trois mécanismes se complètent, et aucun ne remplace les deux autres.

Mécanisme Ce qu'il protège Dans le dépôt
access_grant avec required_access_grants Les champs identifiants Attribut phi_access, valeur yes ou no
access_filter sur chaque explore Les lignes visibles Attribut care_site_access, % pour tout le réseau
Historique des requêtes (System Activity) La traçabilité Qui a interrogé quel champ, quand, sur quel explore

Les deux attributs sont séparés parce qu'ils correspondent à deux rôles : un responsable d'établissement voit toutes les lignes de son site sans voir les identifiants. hidden: yes n'est pas une protection, le champ reste interrogeable par l'API et par les agents.

Quels champs protéger ? La règle Safe Harbor de la loi américaine HIPAA liste dix-huit catégories d'identifiants, dont les noms, tout élément de date autre que l'année (naissance, admission, sortie, décès), les âges au-delà de 89 ans et toute subdivision géographique plus fine que l'État. Le dépôt applique cette grille : identifiant source, date de naissance, dates de décès et code postal portent le grant ; année de naissance, tranche d'âge (dont la dernière, 85 ans et plus, absorbe la règle des 89 ans), indicateur de décès et État restent ouverts ; la couche staging ne charge jamais les lignes d'adresse. En France, le RGPD et le régime de l'hébergement de données de santé s'ajoutent à ce socle, mais la mécanique dans Looker est la même.

Pourquoi des données synthétiques

Le dépôt tourne sur bigquery-public-data.cms_synthetic_patient_data_omop. Ce jeu de données est le DE-SynPUF des CMS, un échantillon synthétique de bénéficiaires Medicare de 2008 et de leurs remboursements de 2008 à 2010, construit par des techniques de limitation de la divulgation à partir de bénéficiaires réels, converti au format OMOP CDM 5.2 par la communauté OHDSI et publié par Google. Environ deux millions de patients synthétiques, aucune donnée de santé réelle.

Les grants et le filtre par établissement ne protègent donc rien de réel dans la démonstration. Ils y figurent parce que le motif doit exister avant l'arrivée des données réelles, pas après.

Le dépôt de référence, pas à pas

Le code est public : looker-semantic-layer-health, sous licence MIT, déployable en un quart d'heure sur un projet Google Cloud.

dbt. Treize modèles staging, une couche intermediate qui classe les visites (int_encounters_classified), calcule les fenêtres de réadmission (int_readmissions), étend les groupes de concepts chroniques et agrège les faits par patient, puis six marts : fct_encounters, fct_diagnoses, dim_patients, dim_providers, dim_care_sites, dim_dates. Le glossaire dbt/metrics.md liste dix-sept métriques M1 à M17.

LookML. Trois explores (encounters, diagnoses, patients), tous en many_to_one, et les faits ne se joignent jamais entre eux : le type de visite et l'établissement dont l'explore des diagnostics a besoin sont dénormalisés sur fct_diagnoses par dbt. Un datagroup, health_daily. Une table dérivée, condition_volume_rank, pour le classement « vingt premières pathologies contre longue traîne ». Toutes les dates en datatype: date et convert_tz: no, parce que le modèle stocke des dates calendaires et qu'un décalage de fuseau casserait l'élagage des partitions.

Tableau de bord. clinical_operations, six tuiles et trois filtres, chaque titre portant l'identifiant du glossaire.

Intégration continue. Un linter LookML (descriptions obligatoires, relationship sur chaque jointure, pas de date en dur, une clé primaire par vue), puis dbt build incrémental sur les pull requests.

FAQ

Notre entrepôt n'est pas au format OMOP, le dépôt sert-il quand même ?

Oui pour tout ce qui est en aval de staging : les fenêtres de réadmission, la durée de séjour, la séparation entre droits de ligne et droits de champ ne dépendent pas d'OMOP. Ce qui change est la couche staging et, sans vocabulaire standardisé, la définition des groupes chroniques, qui redevient une liste de codes à maintenir.

Pourquoi le taux du dépôt ne correspond-il pas à l'indicateur officiel ?

Parce que l'indicateur officiel est ajusté au risque et exclut les réadmissions planifiées, ce qu'une couche sémantique de pilotage n'a pas à reproduire. Le bon usage est de suivre un taux brut défini une fois, stable dans le temps, et de laisser le calcul réglementaire à la chaîne qui en a la charge.

Peut-on brancher un agent conversationnel sur ces données ?

C'est précisément le cas où la couche sémantique compte le plus. L'agent hérite des grants, des filtres de ligne et des descriptions ; un modèle où les identifiants ne sont que masqués et où « diabétique » est une recherche de texte produirait des réponses fausses et des fuites. Le modèle du dépôt est construit pour que la réponse de l'agent soit celle du tableau de bord.

Et ensuite

Si votre comité de pilotage compare des taux de réadmission calculés dans trois outils, commencez par le tableau des cinq choix ci-dessus : une colonne par option retenue, une signature du directeur médical. Le dépôt montre ensuite comment ces choix deviennent deux drapeaux testés et une mesure.

Voir l'offre Couche sémantique BigQuery, dbt, Looker, et pour aller plus loin : Couche sémantique : pourquoi vos chiffres ne concordent pas et Les prérequis de Conversational Analytics.

Sources

Tous les guides