Tutoriel Python - Usage de la Base sur la Qualité et la Sécurité des Soins (BQSS)#
Ce notebook vise à montrer un usage type dont peut être l’objet BQSS, de façon programmatique grâce au langage Python.
Import des librairies et des données#
Les URLS des données sont récupérable sur la page de la Base sur la Qualité et la Sécurité des Soins sur la plateforme Data Gouv accessible via ce lien. La section Fichiers contient les données disponibles, et pour chaque fichier, une description est présente incluant notamment un URL stable qu’il est recommandé d’utiliser.
La base BQSS adoptant un format clé-valeurs, il est nécessaire de récupérer la table des valeurs d’intérêts (concernant la qualité et la sécurité des soins) ainsi que les métadonnées associées spécifiant ces valeurs et les données caractérisant les établissements de santé via les numéro FINESS.
import numpy as np
import pandas as pd # version >= 1.4.2
# chargement du fichier valeurs.csv dans un dataframe pandas
valeurs_df = pd.read_csv(
"https://www.data.gouv.fr/fr/datasets/r/da295ccc-2011-4995-b810-ad1f1a82a83f",
low_memory=False,
)
# chargement du fichier metadata.csv dans un dataframe pandas
metadata_df = pd.read_csv(
"https://www.data.gouv.fr/fr/datasets/r/e56fb5a5-5a74-4507-ba77-e0411d4aa234",
low_memory=False,
)
# chargement du fichier finess.csv dans un dataframe pandas
finess_df = pd.read_csv(
"https://www.data.gouv.fr/fr/datasets/r/48dadbce-56a8-4dc4-ac51-befcdfd82521",
low_memory=False,
)
Observation des données#
Il est désormais possible de consulter les informations caractérisant ces données et en observer un échantillon.
Caractérisation des données valeurs_df#
valeurs_df.info()
valeurs_df.sample(n=5, random_state=187)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3091251 entries, 0 to 3091250
Data columns (total 10 columns):
# Column Dtype
--- ------ -----
0 annee int64
1 finess object
2 finess_type object
3 key object
4 value_boolean object
5 value_string object
6 value_integer float64
7 value_float float64
8 missing_value object
9 value_date object
dtypes: float64(2), int64(1), object(7)
memory usage: 235.8+ MB
annee | finess | finess_type | key | value_boolean | value_string | value_integer | value_float | missing_value | value_date | |
---|---|---|---|---|---|---|---|---|---|---|
2268814 | 2021 | 170780068 | geo | psy_smhosp_qls_2021-qls_classe | NaN | NaN | NaN | NaN | Non concerné | NaN |
1598279 | 2021 | 2B0000020 | jur | mco_dpa_pcd_2018-pcd_evolution | NaN | NaN | NaN | NaN | Non concerné | NaN |
2703023 | 2017 | 620000257 | geo | classement_48h | NaN | NaN | NaN | NaN | Données insuffisantes | NaN |
1558517 | 2022 | 410000293 | geo | mco_ca_reh303c27_2022-reh3_03c27_ratio | NaN | NaN | NaN | NaN | Non concerné | NaN |
1569137 | 2022 | 130784481 | geo | mco_ca_reh307c14_2022-reh3_07c14_ratio | NaN | NaN | NaN | NaN | Non concerné | NaN |
Un grand nombre de variables de nature différente sont regroupées dans cette table (d’où la table metadata venant spécifier la nature de chaque variables). Le nom des variables est stocké dans la colonne key
.
Afin de pouvoir distinguer les différents types de valeurs (booléen, entier, décimal, chaîne de caractères, valeurs manquantes, dates), des colonnes dédiées leur sont attachées.
Ainsi, pour une variable donnée, un seul type est possible… :
sur l’ensemble de la classe (hormis la colonne
missing_value
)pour chaque valeur (justifiant la nature lacunaire de ces colonnes, toutes les colonnes autre que celle prenant la valeur étant à NaN)
Caractérisation des données metadata_df#
metadata_df.info()
metadata_df.sample(n=5, random_state=123)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 907 entries, 0 to 906
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 907 non-null object
1 title 907 non-null object
2 description 289 non-null object
3 type 907 non-null object
4 source 907 non-null object
5 indicateur 722 non-null object
6 secteur 722 non-null object
7 theme 722 non-null object
8 acronyme 655 non-null object
9 version 663 non-null float64
10 variable 663 non-null object
11 annee 663 non-null float64
12 ancienne_variable 663 non-null object
13 url_rapport 582 non-null object
14 type_metier 841 non-null object
15 finess_type 907 non-null object
dtypes: float64(2), object(14)
memory usage: 113.5+ KB
name | title | description | type | source | indicateur | secteur | theme | acronyme | version | variable | annee | ancienne_variable | url_rapport | type_metier | finess_type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
646 | ssr_dpa_dtn1_2015-resultat_dtn1 | Résultat du contrôle dépistage de troubles nut... | NaN | classe | IQSS dossier patient | SSR_DPA_DTN1_2015 | SSR | DPA | DTN1 | 2015.0 | resultat_dtn1 | 2015.0 | resultat_dtn1 | https://www.has-sante.fr/upload/docs/applicati... | controle | mixte |
384 | mco_dpa_qls_2021-qls_ichaut | Borne haute de l'IC associé au résultat de l'i... | NaN | float-string | IQSS dossier patient | MCO_DPA_QLS_2021 | MCO | DPA | QLS | 2021.0 | qls_ichaut | 2021.0 | ic_haut_dpa_qls_v3_mco | https://www.has-sante.fr/upload/docs/applicati... | intervalle_haut | mixte |
553 | psy_ias_icsha_2018-icsha_classe | Classe (Indicateur de consommation de solution... | NaN | classe | IQSS questionnaire établissement | PSY_IAS_ICSHA_2018 | PSY | IAS | ICSHA | 2018.0 | icsha_classe | 2018.0 | classe_ias_icsha_v3_psy | https://pprod-web.has-sante.fr/upload/docs/app... | classe | mixte |
643 | ssr_dpa_dtn1_2015-dtn1_c1_etbt | Valeur dépistage de troubles nutrionnels (2 ni... | NaN | float | IQSS dossier patient | SSR_DPA_DTN1_2015 | SSR | DPA | DTN1 | 2015.0 | dtn1_c1_etbt | 2015.0 | dtn1_c1_etbt | https://www.has-sante.fr/upload/docs/applicati... | resultat_min | mixte |
498 | mco_pcc_pcc_2021-pcc_evolution | Evolution de l'indicateur par rapport au recue... | NaN | int-string | IQSS dossier patient | MCO_PCC_PCC_2021 | MCO | PCC | PCC | 2021.0 | pcc_evolution | 2021.0 | evol_pcc_pcc_mco | https://www.has-sante.fr/upload/docs/applicati... | evolution | mixte |
La colonne name
de cette table permet de faire la jointure avec la table valeurs_df
via la colonne key
associée.
Les métadonnées permettent de compléter les informations associées aux variables, en particulier leur type
(encodé implicitement dans valeur.csv
, voir ci-dessus), leur source
(provenant d’origines variées), leur secteur
, leur theme
et leur acronyme
.
Pour une recherche rapide, vous pouvez aussi utiliser directement le fichier metadata.xlsx
qui permet de faire des filtres rapides sur les différentes colonnes.
Caractérisation des données finess_df#
finess_df.info()
finess_df.sample(n=5, random_state=123)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 183719 entries, 0 to 183718
Data columns (total 56 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date_export 183719 non-null object
1 num_finess_et 183719 non-null object
2 num_finess_ej 183719 non-null object
3 raison_sociale_et 183719 non-null object
4 raison_sociale_longue_et 131719 non-null object
5 complement_raison_sociale 23120 non-null object
6 complement_distribution 28442 non-null object
7 num_voie 139085 non-null object
8 type_voie 171873 non-null object
9 libelle_voie 176732 non-null object
10 complement_voie 5612 non-null object
11 lieu_dit_bp 32176 non-null object
12 commune 9001 non-null float64
13 departement 183719 non-null object
14 libelle_departement 183719 non-null object
15 ligne_acheminement 183719 non-null object
16 telephone 162205 non-null object
17 telecopie 104176 non-null object
18 categorie_et 183719 non-null int64
19 libelle_categorie_et 183719 non-null object
20 categorie_agregat_et 183719 non-null int64
21 libelle_categorie_agregat_et 183719 non-null object
22 siret 153064 non-null float64
23 code_ape 85791 non-null object
24 code_mft 183719 non-null int64
25 libelle_mft 183719 non-null object
26 code_sph 182641 non-null float64
27 libelle_sph 182641 non-null object
28 date_ouverture 183719 non-null object
29 date_autorisation 183719 non-null object
30 date_maj 183719 non-null object
31 num_uai 2570 non-null object
32 coord_x_et 116403 non-null float64
33 coord_y_et 116401 non-null float64
34 source_coord_et 116089 non-null object
35 date_geocodage 118851 non-null object
36 region 174718 non-null float64
37 libelle_region 174718 non-null object
38 code_officiel_geo 174718 non-null object
39 code_postal 183719 non-null int64
40 libelle_routage 174718 non-null object
41 libelle_code_ape 79852 non-null object
42 ferme_cette_annee 183719 non-null bool
43 latitude 116074 non-null float64
44 longitude 116074 non-null float64
45 libelle_commune 183719 non-null object
46 adresse_postale_ligne_1 137414 non-null object
47 adresse_postale_ligne_2 183719 non-null object
48 raison_sociale_ej 183719 non-null object
49 raison_sociale_longue_ej 147125 non-null object
50 statut_juridique_ej 183719 non-null int64
51 libelle_statut_juridique_ej 183719 non-null object
52 statut_juridique 183719 non-null object
53 type_etablissement 183719 non-null object
54 actif_qualiscope 183719 non-null bool
55 dernier_enregistrement 183719 non-null bool
dtypes: bool(3), float64(8), int64(5), object(40)
memory usage: 74.8+ MB
date_export | num_finess_et | num_finess_ej | raison_sociale_et | raison_sociale_longue_et | complement_raison_sociale | complement_distribution | num_voie | type_voie | libelle_voie | ... | adresse_postale_ligne_1 | adresse_postale_ligne_2 | raison_sociale_ej | raison_sociale_longue_ej | statut_juridique_ej | libelle_statut_juridique_ej | statut_juridique | type_etablissement | actif_qualiscope | dernier_enregistrement | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
165553 | 2019-12-31 | 590805925 | 590781605 | CMP ENFANTS CAUDRY CH CAMBRAI | CENTRE MEDICO-PSYCHOLOGIQUE PSY. GENERALE & IN... | NaN | 59G37-59I11 | 25 | Rue | GAMBETTA | ... | 25 Rue Gambetta | 59540 CAUDRY | CH CAMBRAI | ETABLISSEMENT PUBLIC DE SANTE DE CAMBRAI | 13 | Etb.Pub.Commun.Hosp. | Public | Public | False | False |
177996 | 2022-12-31 | 400013348 | 400011177 | HOPITAL DE JOUR ADULTES - PARENTIS | HOPITAL DE JOUR POUR ADULTES CH MT MARSAN - PA... | CH DE MONT DE MARSAN | NaN | NaN | Rue | DALIS | ... | NaN | 40160 PARENTIS EN BORN | CHI MONT DE MARSAN ET PAYS DES SOURCES | CHI DE MONT DE MARSAN ET DU PAYS DES SOURCES | 13 | Etb.Pub.Commun.Hosp. | Public | CH | False | False |
105354 | 2023-12-31 | 920808920 | 780140059 | HDJ LE PARC NANTERRE | HOPITAL DE JOUR LE PARC NANTERRE | NaN | NaN | 39 | Rue | VOLANT | ... | 39 Rue Volant | 92000 NANTERRE | CH THEOPHILE ROUSSEL | CENTRE HOSPITALIER THEOPHILE ROUSSEL | 12 | Etb.Pub.Intdép.Hosp. | Public | Public | False | False |
81451 | 2007-12-31 | 310796776 | 310000617 | ANTENNE D'AUTODIALYSE REVEL | ANTENNE D'AUTODIALYSE REVEL | NaN | "LE JARDIN DE BEAUSEJOUR" | NaN | NaN | NaN | ... | NaN | 31250 REVEL | SAS CLINIQUE NÉPHRO SAINT EXUPERY | SOCIÉTÉ ACTIONS SIMPLIFIÉES CLINIQUE NÉPHROLOG... | 75 | Autre Société | Privé | Privé | False | False |
59867 | 2013-12-31 | 220000236 | 220017974 | CENTRE HOSPITALIER DE PLOUGUERNEVEL | CENTRE HOSPITALIER DE PLOUGUERNEVEL | NaN | NaN | 2 | Route | DE ROSTRENEN | ... | 2 Route De Rostrenen | 22110 PLOUGUERNEVEL | ASSOCIATION HOSPITALIERE DE BRETAGNE | ASSOCIATION HOSPITALIERE DE BRETAGNE | 60 | Ass.L.1901 non R.U.P | Privé à but non lucratif | Privé à but non lucratif | False | False |
5 rows × 56 columns
Cette table contient l’ensemble des données Finess historisées. Il y a une ligne par export et par Finess présent à la date de l’export. Pour un même Finess il ya donc très souvent plusieurs lignes.
Les colonnes qui s’avèrent souvent utiles sont:
num_finess_et
: numéro finess géographiquenum_finess_ej
: numéro finess juridiquelatitude
etlongitude
: les coordonnées géographiques de l’établissement dans le référentiel WGS84raison_sociale_et
: le nom de l’établissementdernier_enregistrement
: indique si cette ligne est la dernière connue pour le finess en question
Préparation des données#
Récupération des clés associées à des catégories de valeurs#
Les cas d’usages pour lesquels la base est utilisé ne concernent souvant qu’un sous-ensemble des domaines présents dans la base. On peut par exemple vouloir récupérer l’historique complet des IQSS issus du questionnaire patient (ESATIS).
La mécanique pour sélectionner le sous ensemble de données d’interêt est la suivante:
Dans le fichier
metadata.csv
utiliser la colonnesource
pour identifier le domaine d’intérêtDans le fichier
metadata.csv
recupérer le nom des variables de lasource
donnée qui sont stockées dans la colonnename
Parmis ces variables, utiliser les colonne
type_metier
(pour les IQSS) et/oudescription
pour sélectionner les variables d’intérêtDans le fichier
valeurs.csv
sélection toutes les lignes dont la colonnekey
contient une variable du domaine d’intérêt
Ci-dessous un exemple de cette mécanique:
# Affichage des sources de données existantes
metadata_df["source"].value_counts()
source
IQSS dossier patient 600
SAE 119
IQSS questionnaire patient 59
IQSS PMSI 42
Certification v2014 33
Certification v2021 22
IQSS questionnaire établissement 21
Activités ET 11
Name: count, dtype: int64
# Récupération des noms des variables de certification v2014
certif_14_keys = metadata_df[metadata_df["source"] == "Certification v2014"][
"name"
]
# Récupération des nom des variables esatis
esatis_keys = metadata_df[
metadata_df["source"] == "IQSS questionnaire patient"
]["name"]
# Affichage des types métiers certification
# Les variables de certification n'ont pas de type métier
metadata_df.loc[
metadata_df["name"].isin(certif_14_keys),
["name", "description", "type_metier"],
].head(5)
name | description | type_metier | |
---|---|---|---|
0 | certif_V2014_id_niveau | Code du niveau de certification validé par le ... | NaN |
1 | certif_date | Date de délibération du collège de la HAS qui ... | NaN |
2 | certif_V2014_id_demarche | Code interne à la HAS. Il s'agit d'un code per... | NaN |
3 | certif_V2014_decision_thematique_1 | Décision finale pour la thématique : Managemen... | NaN |
4 | certif_V2014_decision_thematique_2 | Décision finale pour la thématique : Qualité d... | NaN |
# Affichage des types métiers esatis
metadata_df.loc[
metadata_df["name"].isin(esatis_keys),
["name", "description", "type_metier"],
].head(5)
name | description | type_metier | |
---|---|---|---|
718 | nb_rep_score_all_rea_ajust | Nombre de réponses concernant la satisfaction ... | effectif_observe |
719 | score_all_rea_ajust | Note ajustée de satisfaction globale classemen... | score |
720 | score_all_rea_ajust_dp | Note ajustée de satisfaction globale classemen... | score_arrondi |
721 | score_ajust_esatis_region_48h | Note ajustée de satisfaction globale des patie... | moyenne_regionale |
722 | score_ajust_esatis_type_48h | Note ajustée de satisfaction globale des patie... | moyenne_nationale |
# Affichage des variables de type score pour esatis
metadata_df.loc[
metadata_df["name"].isin(esatis_keys)
& (metadata_df["type_metier"] == "score"),
["name", "description", "type_metier"],
]
name | description | type_metier | |
---|---|---|---|
719 | score_all_rea_ajust | Note ajustée de satisfaction globale classemen... | score |
726 | score_accueil_rea_ajust | Note ajustée concernant la satisfaction de l'a... | score |
728 | score_pecinf_rea_ajust | Note ajustée de satisfaction de la prise en ch... | score |
730 | score_pecmed_rea_ajust | Note ajustée de satisfaction de la prise en ch... | score |
732 | score_chambre_rea_ajust | Note ajustée de satisfaction de la chambre | score |
734 | score_repas_rea_ajust | Note ajustée de satisfaction des repas | score |
736 | score_sortie_rea_ajust | Note ajustée de satisfaction de la sortie | score |
737 | taux_reco_brut_48h | Pourcentage de patients recommandant certainem... | score |
740 | score_all_ajust_ca | Score de satisfaction globale ajusté | score |
746 | score_avh_ajust | Note ajustée de la satisfaction avant l'hospit... | score |
748 | score_acc_ajust | Note ajustée concernant la satisfaction accuei... | score |
750 | score_pec_ajust | Note ajustée de la satisfaction de la prise en... | score |
752 | score_cer_ajust | Note ajustée de la satisfaction chambre et rep... | score |
754 | score_ovs_ajust | Note ajustée de la satisfaction sortie et reto... | score |
756 | taux_reco_brut_ca | Pourcentage de patients recommandant certainem... | score |
759 | score_all_ssr_ajust | Score de satisfaction globale ajusté | score |
765 | score_accueil_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
767 | score_pec_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
769 | score_lieu_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
771 | score_repas_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
773 | score_sortie_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
775 | taux_reco_brut_ssr | Pourcentage de patients recommandant certainem... | score |
Isolation des domaines de données#
Afin de pouvoir préparer et analyser un domaine de données, il est nécessaire de l’isoler en vue de traitements décrits plus bas. Pour des raisons de volumétrie, le présent tutoriel se restreint aux données esatis. Mais il est naturellement possible d’effectuer ces analyses sur un ensemble de domaines de données, voire sur tous les domaines (les mêmes opérations décrites ici peuvent leur être appliquées).
# Isolation du domaine de données esatis
esatis_df = valeurs_df[valeurs_df["key"].isin(esatis_keys)]
# Isolation du domaine de données certification v2014, pour illustration
certif_df = valeurs_df[valeurs_df["key"].isin(certif_14_keys)]
Pivot de la table esatis#
Actuellement, le format clé-valeur de la base induit que chaque valeur de chaque variable pour chacun des établissements est associée à une ligne. Nous souhaitons pourvoir avoir un regroupement des valeurs pour chaque établissement.
Pour cela, nous devons effectuer les opérations suivantes (cf. cellule de code ci-dessous) :
Effectuer un pivot à la table pour avoir une colonne par variable (par type), chaque ligne représentant un établissement pour une année donnée (puisque certaines valeurs sont collectées annuellement)
Chaque classe de valeur n’ayant qu’un type de valeur acceptable (hormis le type
missing_value
), toutes les colonnes des autres types seront remplis deNaN
=> il s’agit donc également de supprimer ces colonnes inutilesLes colonnes des valeurs manquantes pour une clé sont fusionnées avec la colonne de valeurs de la clé correspondante pour ne pas perdre l’information correspondante
# Les colonnes de valeurs sont pivotées selon le colonne key, pour chaque triplet (annee, finess, finess_type)
esatis_df = esatis_df.pivot(
index=["annee", "finess", "finess_type"], columns="key"
)
# Toutes les colonnes de valeurs liées à un type incorrect vis-à-vis du type attendu sont remplies par des NaN.
# Il s'agit ici de supprimer ces colonnes qui ne portent aucune information exploitable
esatis_df = esatis_df.dropna(axis=1, how="all")
# Les colonnes associées au type missing_value sont fusionnées avec leur colonne de valeur respective
# Cette étape est optionnelle si les valeurs manquantes sont sans intérêts pour l'étude
if "missing_value" in esatis_df:
esatis_df = esatis_df.combine_first(esatis_df["missing_value"]).drop(
columns="missing_value"
)
# Les colonnes qui résultent de ces opérations ont plusieurs niveaux qui sont ici applatis pour n'en avoir plus qu'un
esatis_df = esatis_df.droplevel(0, axis=1)
# Les données d'années, de finess et de finess_type utilisées jusqu'ici comme index sont basculées en colonnes dans la table.
esatis_df = esatis_df.reset_index()
Un échantillon de la table résultante peut être observée ci-dessous, en notant qu’il manque des données pour de nombreux établissements sur certaines années car certains indicateurs n’étaient pas calculés à ce moment là.
esatis_df.sample(n=5, random_state=123)
key | annee | finess | finess_type | classement_48h | classement_ca | classement_ssr | evolution_48h | evolution_ca | evolution_ssr | nb_reco_brut_48h | ... | score_pec_ssr_ajust | score_pecinf_rea_ajust | score_pecmed_rea_ajust | score_repas_rea_ajust | score_repas_ssr_ajust | score_sortie_rea_ajust | score_sortie_ssr_ajust | taux_reco_brut_48h | taux_reco_brut_ca | taux_reco_brut_ssr |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1129 | 2016 | 970107249 | geo | Données insuffisantes | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2721 | 2018 | 420000192 | geo | Données insuffisantes | NaN | NaN | 4-Non calculable | NaN | NaN | NaN | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN | NaN | NaN |
4686 | 2020 | 040780470 | geo | A | B | NaN | NaN | NaN | NaN | 40.0 | ... | NaN | 87.86 | 87.21 | 68.11 | NaN | 74.31 | NaN | 80.0 | 64.4 | NaN |
2467 | 2018 | 170780621 | geo | Données insuffisantes | Données insuffisantes | NaN | 4-Non calculable | NaN | NaN | NaN | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN | NaN | NaN |
9788 | 2023 | 450010079 | geo | B | B | NaN | 0.0 | 0.0 | NaN | 1090.0 | ... | NaN | 82.72 | 82.12 | 60.37 | NaN | 66.89 | NaN | 64.9 | 68.7 | NaN |
5 rows × 62 columns
Exploitation des données#
Dans cette section, une analyse simple sur le domaine esatis est effectuée à des fins d’illustration quant à la valorisation de ces données.
Le cas d’usage de cette analyse est l’observation de l’évolution du positionnement national d’un établissement identifié (il s’agit ici de l’établissement associé au finess n°060000478
) vis-à-vis des établissements de même catégorie (il s’agit ici de la catégorie Centres Hospitaliers, associée au code 1102
) sur l’indicateur score_all_ajust_ca
(correspondant au “score de satisfaction globale ajusté” en chirurgie ambulatoire).
Pour ce faire, il faut :
associer aux données esatis les données finess nécessaires à la jointure et à la catégorisation des établissements
calculer le classement de l’établissement (son rang absolu et le pourcentage associé) pour chaque année
représenter la distribution des établissements pour chaque année en positionnant l’établissement étudié
Ces étapes sont réalisées dans les deux sections ci-dessous.
Finalisation de la préparation des données#
# On ne prend que les informations des finess les plus récentes pour éviter les doublons à la jointure
finess_df = finess_df.loc[finess_df["dernier_enregistrement"]]
# Jointure entre les données esatis et les données Finess restreintes aux agrégats de catégories d'établissement
df = finess_df[
[
"num_finess_et",
"categorie_agregat_et",
"raison_sociale_et",
"departement",
]
].merge(esatis_df, left_on="num_finess_et", right_on="finess", how="inner")
df.sample(5, random_state=123)
num_finess_et | categorie_agregat_et | raison_sociale_et | departement | annee | finess | finess_type | classement_48h | classement_ca | classement_ssr | ... | score_pec_ssr_ajust | score_pecinf_rea_ajust | score_pecmed_rea_ajust | score_repas_rea_ajust | score_repas_ssr_ajust | score_sortie_rea_ajust | score_sortie_ssr_ajust | taux_reco_brut_48h | taux_reco_brut_ca | taux_reco_brut_ssr | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
9433 | 900000035 | 1110 | HOPITAL PRIVE DE LA MIOTTE | 90 | 2018 | 900000035 | geo | B | B | NaN | ... | NaN | 82.35 | 83.42 | 64.98 | NaN | 70.79 | NaN | NaN | NaN | NaN |
7246 | 710978255 | 1102 | CH ALIGRE BOURBON LANCY | 71 | 2018 | 710978255 | geo | Données insuffisantes | NaN | NaN | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN | NaN | NaN |
9289 | 870000411 | 1110 | CLINIQUE EMAILLEURS-COLOMBIER LIMOGES | 87 | 2019 | 870000411 | geo | B | D | NaN | ... | NaN | 83.06 | 80.98 | 63.31 | NaN | 66.76 | NaN | 69.3 | 55.5 | NaN |
2540 | 310780150 | 1110 | CL MEDIPOLE GARONNE TOULOUSE | 31 | 2022 | 310780150 | geo | A | A | NaN | ... | NaN | 85.98 | 86.0 | 66.82 | NaN | 69.15 | NaN | 78.2 | 81.9 | NaN |
3237 | 350000162 | 1102 | CHIRC SITE REDON | 35 | 2018 | 350000162 | geo | C | Données insuffisantes | NaN | ... | NaN | 84.58 | 80.89 | 63.09 | NaN | 64.51 | NaN | NaN | NaN | NaN |
5 rows × 66 columns
# Seuls les centres hospitaliers sont conservés
df = df[df["categorie_agregat_et"] == 1102]
# Pour cette étude, seules les colonnes suivantes sont nécessaires pour la suite : annee, taux_reco_brut_ca, finess
# Par ailleurs, cet indicateur n'est collecté qu'a partir de 2019.
df = df.loc[
df["annee"] >= 2019,
[
"annee",
"finess",
"raison_sociale_et",
"departement",
"score_all_ajust_ca",
],
]
# Les établissements sans valeurs pour l'indicateur sont retirés
df = df.dropna()
Un extrait de la table correspondante peut être observée :
df.sample(5, random_state=123)
annee | finess | raison_sociale_et | departement | score_all_ajust_ca | |
---|---|---|---|---|---|
4545 | 2021 | 510000169 | CENTRE HOSPITALIER LEON BOURGEOIS | 51 | 79.15 |
2711 | 2022 | 330000555 | CENTRE HOSPITALIER D'ARCACHON | 33 | 79.3 |
1735 | 2020 | 220000368 | CENTRE HOSPITALIER LANNION | 22 | 82.86 |
4137 | 2021 | 450000047 | CH DEZARNAULDS - GIEN | 45 | Données insuffisantes |
2957 | 2020 | 340000033 | CH BEZIERS | 34 | 76.21 |
Visualisation des résultats#
es_finess = "060000478"
axes = df.plot.hist(by="annee", bins=20, figsize=(10, 15), legend=False)
for i, annee in enumerate(np.sort(df["annee"].unique())):
axes[i].set_xlim(0, 100)
axes[i].set_ylim(0, 37)
axes[i].set_ylabel("Fréquences", fontsize=12)
df_tmp = (
df[df["annee"] == annee]
.sort_values("score_all_ajust_ca", ascending=False)
.reset_index()
)
value = df_tmp.loc[
df_tmp["finess"] == es_finess, "score_all_ajust_ca"
].values[0]
axes[i].axvline(value, color="red")
axes[i].text(value - 3.2, -4.5, str(value), color="red", fontsize=12)
axes[i].text(
value + 1, 38, "finess n°" + str(es_finess), color="red", fontsize=12
)
rank = df_tmp[df_tmp["finess"] == es_finess].index.item() + 1
card_finess = df_tmp.shape[0]
rank_ratio = 100 * rank / card_finess
axes[i].text(
5,
30,
f"classement : {rank} / {card_finess}\nposition (%) : {rank_ratio:,.1f}",
backgroundcolor="lightgrey",
color="red",
fontsize=12,
fontweight="roman",
)
axes[2].set_xlabel(
"score de satisfaction globale ajusté",
fontsize=12,
labelpad=15,
)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[16], line 2
1 es_finess = "060000478"
----> 2 axes = df.plot.hist(by="annee", bins=20, figsize=(10, 15), legend=False)
3 for i, annee in enumerate(np.sort(df["annee"].unique())):
4 axes[i].set_xlim(0, 100)
File ~/.cache/pypoetry/virtualenvs/bqss-9TtSrW0h-py3.11/lib/python3.11/site-packages/pandas/plotting/_core.py:1412, in PlotAccessor.hist(self, by, bins, **kwargs)
1350 def hist(
1351 self, by: IndexLabel | None = None, bins: int = 10, **kwargs
1352 ) -> PlotAccessor:
1353 """
1354 Draw one histogram of the DataFrame's columns.
1355
(...)
1410 >>> ax = df.plot.hist(column=["age"], by="gender", figsize=(10, 8))
1411 """
-> 1412 return self(kind="hist", by=by, bins=bins, **kwargs)
File ~/.cache/pypoetry/virtualenvs/bqss-9TtSrW0h-py3.11/lib/python3.11/site-packages/pandas/plotting/_core.py:1031, in PlotAccessor.__call__(self, *args, **kwargs)
1028 label_name = label_kw or data.columns
1029 data.columns = label_name
-> 1031 return plot_backend.plot(data, kind=kind, **kwargs)
File ~/.cache/pypoetry/virtualenvs/bqss-9TtSrW0h-py3.11/lib/python3.11/site-packages/pandas/plotting/_matplotlib/__init__.py:71, in plot(data, kind, **kwargs)
69 kwargs["ax"] = getattr(ax, "left_ax", ax)
70 plot_obj = PLOT_CLASSES[kind](data, **kwargs)
---> 71 plot_obj.generate()
72 plot_obj.draw()
73 return plot_obj.result
File ~/.cache/pypoetry/virtualenvs/bqss-9TtSrW0h-py3.11/lib/python3.11/site-packages/pandas/plotting/_matplotlib/core.py:451, in MPLPlot.generate(self)
449 def generate(self) -> None:
450 self._args_adjust()
--> 451 self._compute_plot_data()
452 self._setup_subplots()
453 self._make_plot()
File ~/.cache/pypoetry/virtualenvs/bqss-9TtSrW0h-py3.11/lib/python3.11/site-packages/pandas/plotting/_matplotlib/core.py:636, in MPLPlot._compute_plot_data(self)
634 # no non-numeric frames or series allowed
635 if is_empty:
--> 636 raise TypeError("no numeric data to plot")
638 self.data = numeric_data.apply(self._convert_to_ndarray)
TypeError: no numeric data to plot
⚠️ Attention : L’analyse et l’interprétation des résultats des IQSS nécessite de bien prendre connaissance de leur définition.
Nous pouvons constater que l’établissement considéré dans cette étude a:
Amélioré son score (de
77.73
à80.78
)Amélioré sa place dans la distribution de
54.6
ème percentile à24.3
ème percentile