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: 3798334 entries, 0 to 3798333
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: 289.8+ MB
annee | finess | finess_type | key | value_boolean | value_string | value_integer | value_float | missing_value | value_date | |
---|---|---|---|---|---|---|---|---|---|---|
297965 | 2020 | 380000067 | geo | filtre_chimio | True | NaN | NaN | NaN | NaN | NaN |
1978381 | 2021 | 970404018 | geo | mco_dpa_pcd_2018-pcd_moyenne_regionale | NaN | NaN | NaN | NaN | Non concerné | NaN |
3615213 | 2024 | 530005768 | geo | certification_ref_2021_score_objectif_3.7 | NaN | NaN | NaN | 93.1 | NaN | NaN |
1556881 | 2019 | 950300244 | geo | mco_isoortho_isoortho_2019-iso_ortho_alerte_sup | NaN | NaN | 0.0 | NaN | NaN | NaN |
3194212 | 2024 | 140026709 | geo | score_accueil_ssr_ajust | NaN | NaN | NaN | NaN | Données insuffisantes | 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: 959 entries, 0 to 958
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 name 959 non-null object
1 title 959 non-null object
2 description 293 non-null object
3 type 959 non-null object
4 source 959 non-null object
5 indicateur 770 non-null object
6 secteur 770 non-null object
7 theme 770 non-null object
8 acronyme 703 non-null object
9 version 711 non-null float64
10 variable 711 non-null object
11 annee 711 non-null float64
12 ancienne_variable 711 non-null object
13 url_rapport 582 non-null object
14 type_metier 889 non-null object
15 finess_type 959 non-null object
dtypes: float64(2), object(14)
memory usage: 120.0+ KB
name | title | description | type | source | indicateur | secteur | theme | acronyme | version | variable | annee | ancienne_variable | url_rapport | type_metier | finess_type | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
246 | mco_ca_epssv2_2023-ca_epss_v2_moy_nat | Moyenne nationale de l'indicateur (Évaluation ... | NaN | float-string | IQSS dossier patient | MCO_CA_EPSSV2_2023 | MCO | CA | CA | 2023.0 | moy_nat_ca_ca_epss_v2_mco | 2023.0 | moy_nat_ca_ca_epss_v2_mco | NaN | moyenne_nationale | mixte |
188 | mco_avc_epr1_2014-epr1_c1_ichaut_etbt | Intervalle de confiance haut de l'évaluation p... | NaN | int | IQSS dossier patient | MCO_AVC_EPR1_2014 | MCO | AVC | EPR1 | 2014.0 | epr1_c1_ichaut_etbt | 2014.0 | epr1_c1_ichaut_etbt | https://www.has-sante.fr/upload/docs/applicati... | intervalle_haut | mixte |
392 | mco_dpa_dtn1_2015-dtn1_c1_den_etbt | Dénominateur dépistage de troubles nutrionnels... | NaN | float | IQSS dossier patient | MCO_DPA_DTN1_2015 | MCO | DPA | DTN1 | 2015.0 | dtn1_c1_den_etbt | 2015.0 | dtn1_c1_den_etbt | https://www.has-sante.fr/upload/docs/applicati... | denominateur | mixte |
518 | mco_isoortho_ptg_2020-iso_ptg_alerte_sup | Position de l'établissement par rapport à la b... | NaN | int-string | IQSS PMSI | MCO_ISOORTHO_PTG_2020 | MCO | ISOORTHO | PTG | 2020.0 | iso_ptg_alerte_sup | 2020.0 | iso_ptg_alerte_sup | https://www.has-sante.fr/upload/docs/applicati... | status | mixte |
662 | ssr_avc_snutv2_2022-snut_v2_ic_haut | Borne haute de l'IC associé au résultat de l'i... | NaN | float-string | IQSS dossier patient | SSR_AVC_SNUTV2_2022 | SSR | AVC | SNUTV2 | 2022.0 | ic_haut_avc_snut_v2_ssr | 2022.0 | ic_haut_avc_snut_v2_smr | NaN | intervalle_haut | 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: 2158643 entries, 0 to 2158642
Data columns (total 56 columns):
# Column Dtype
--- ------ -----
0 date_export object
1 num_finess_et object
2 num_finess_ej object
3 raison_sociale_et object
4 raison_sociale_longue_et object
5 complement_raison_sociale object
6 complement_distribution object
7 num_voie object
8 type_voie object
9 libelle_voie object
10 complement_voie object
11 lieu_dit_bp object
12 commune float64
13 departement object
14 libelle_departement object
15 ligne_acheminement object
16 telephone object
17 telecopie object
18 categorie_et int64
19 libelle_categorie_et object
20 categorie_agregat_et int64
21 libelle_categorie_agregat_et object
22 siret float64
23 code_ape object
24 code_mft float64
25 libelle_mft object
26 code_sph float64
27 libelle_sph object
28 date_ouverture object
29 date_autorisation object
30 date_maj object
31 num_uai object
32 coord_x_et float64
33 coord_y_et float64
34 source_coord_et object
35 date_geocodage object
36 region float64
37 libelle_region object
38 code_officiel_geo object
39 code_postal int64
40 libelle_routage object
41 libelle_code_ape object
42 ferme_cette_annee bool
43 latitude float64
44 longitude float64
45 libelle_commune object
46 adresse_postale_ligne_1 object
47 adresse_postale_ligne_2 object
48 raison_sociale_ej object
49 raison_sociale_longue_ej object
50 statut_juridique_ej float64
51 libelle_statut_juridique_ej object
52 statut_juridique object
53 type_etablissement object
54 actif_qualiscope bool
55 dernier_enregistrement bool
dtypes: bool(3), float64(10), int64(3), object(40)
memory usage: 879.0+ 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
350826 | 2017-12-31 | 440002988 | 440001782 | EHPAD SAINT-PIERRE | EHPAD MAISON DE RETRAITE SAINT PIERRE | NaN | NaN | 98 | Rue | DES MARRONNIERS | ... | 98 Rue Des Marronniers | 44850 LIGNE | ASSOCIATION ST PIERRE | ASSOCIATION DE LA MAISON DE RETRAITE SAINT PIERRE | 60.0 | Ass.L.1901 non R.U.P | Privé à but non lucratif | Privé à but non lucratif | False | False |
2109134 | 2024-12-31 | 590049623 | 590807517 | SAVS LA CHRYSALIDE | LA CHRYSALIDE SERVICE D'ACCOMPAGNEMENT À LA V... | NaN | NaN | 40 | Rue | VERLYCK | ... | 40 Rue Verlyck | 59190 HAZEBROUCK | ASSO LES PAPILLONS BLANCS D'HAZEBROUCK | ASSOCIATION DES PAPILLONS BLANCS D'HAZEBROUCK | 61.0 | Ass.L.1901 R.U.P. | Privé à but non lucratif | Privé à but non lucratif | False | False |
291976 | 2009-12-31 | 610004459 | 610790701 | CCAA (ANTENNE) - MORTAGNE AU PERCHE | CENTRE DE CURE AMBULATOIRE EN ALCOOLOGIE | CENTRE INTERCOM. ACTION SOCIALE | NaN | 4 | Rue | DE LA COMÉDIE | ... | 4 Rue De La Comédie | 61400 MORTAGNE AU PERCHE | ANPAA 61 | ASSOC NATIONALE DE PREVENTION EN ALCOOLOGIE ET... | 60.0 | Ass.L.1901 non R.U.P | Privé à but non lucratif | Privé à but non lucratif | False | False |
983070 | 2012-12-31 | 310006465 | 310006457 | CRECHE LA BALEINE BLEUE | NaN | NaN | NaN | 17 | Rue | DE L'ASPIN | ... | 17 Rue De L'Aspin | 31100 TOULOUSE | ASSOCIATION LA BALEINE BLEUE | NaN | 60.0 | Ass.L.1901 non R.U.P | Privé à but non lucratif | Privé à but non lucratif | False | False |
480216 | 2004-12-31 | 970200085 | 970202206 | CENTRE HOSPITALIER DU CARBET | NaN | NaN | QUARTIER LAJUS | NaN | NaN | NaN | ... | NaN | 97221 LE CARBET | CENTRE HOSPITALIER DU CARBET | NaN | 11.0 | Etb.Pub.Départ.Hosp. | Public | CH | 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 648
SAE 119
IQSS questionnaire patient 59
IQSS PMSI 42
Certification v2014 37
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 | |
---|---|---|---|
770 | nb_rep_score_all_rea_ajust | Nombre de réponses concernant la satisfaction ... | effectif_observe |
771 | score_all_rea_ajust | Note ajustée de satisfaction globale classemen... | score |
772 | score_all_rea_ajust_dp | Note ajustée de satisfaction globale classemen... | score_arrondi |
773 | score_ajust_esatis_region_48h | Note ajustée de satisfaction globale des patie... | moyenne_regionale |
774 | 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 | |
---|---|---|---|
771 | score_all_rea_ajust | Note ajustée de satisfaction globale classemen... | score |
778 | score_accueil_rea_ajust | Note ajustée concernant la satisfaction de l'a... | score |
780 | score_pecinf_rea_ajust | Note ajustée de satisfaction de la prise en ch... | score |
782 | score_pecmed_rea_ajust | Note ajustée de satisfaction de la prise en ch... | score |
784 | score_chambre_rea_ajust | Note ajustée de satisfaction de la chambre | score |
786 | score_repas_rea_ajust | Note ajustée de satisfaction des repas | score |
788 | score_sortie_rea_ajust | Note ajustée de satisfaction de la sortie | score |
789 | taux_reco_brut_48h | Pourcentage de patients recommandant certainem... | score |
792 | score_all_ajust_ca | Score de satisfaction globale ajusté | score |
798 | score_avh_ajust | Note ajustée de la satisfaction avant l'hospit... | score |
800 | score_acc_ajust | Note ajustée concernant la satisfaction accuei... | score |
802 | score_pec_ajust | Note ajustée de la satisfaction de la prise en... | score |
804 | score_cer_ajust | Note ajustée de la satisfaction chambre et rep... | score |
806 | score_ovs_ajust | Note ajustée de la satisfaction sortie et reto... | score |
808 | taux_reco_brut_ca | Pourcentage de patients recommandant certainem... | score |
811 | score_all_ssr_ajust | Score de satisfaction globale ajusté | score |
817 | score_accueil_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
819 | score_pec_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
821 | score_lieu_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
823 | score_repas_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
825 | score_sortie_ssr_ajust | Note ajustée concernant la satisfaction au niv... | score |
827 | 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 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
9880 | 2023 | 520000043 | geo | D | NaN | Données insuffisantes | Non calculable | NaN | NaN | 38.0 | ... | Données insuffisantes | 77.72 | 75.89 | 64.49 | Données insuffisantes | 56.18 | Données insuffisantes | 50.0 | NaN | Données insuffisantes |
3859 | 2019 | 370007569 | geo | B | B | NaN | 0.0 | 0.0 | NaN | 910.0 | ... | NaN | 82.33 | 82.79 | 61.73 | NaN | 67.55 | NaN | 66.3 | 66.5 | NaN |
5701 | 2020 | 910018423 | geo | Données insuffisantes | NaN | NaN | NaN | NaN | NaN | Données insuffisantes | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN |
4453 | 2019 | 830000287 | geo | Non validé | Non validé | NaN | NaN | NaN | NaN | Non validé | ... | NaN | Non validé | Non validé | Non validé | NaN | Non validé | NaN | Non validé | Non validé | NaN |
10199 | 2023 | 650000417 | geo | C | A | NaN | 0.0 | 0.0 | NaN | 363.0 | ... | NaN | 83.03 | 82.3 | 55.32 | NaN | 65.11 | NaN | 44.6 | 75.6 | 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 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11800 | 930300595 | 1110 | HOPITAL PRIVE DU VERT GALANT | 93 | 2022 | 930300595 | geo | D | C | NaN | ... | NaN | 76.54 | 78.79 | 43.71 | NaN | 61.24 | NaN | 34.3 | 58.7 | NaN |
7011 | 620000240 | 1102 | CH HENIN BEAUMONT | 62 | 2018 | 620000240 | geo | Données insuffisantes | NaN | NaN | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN | NaN | NaN |
4785 | 440001113 | 1104 | ICO - SITE GAUDUCHEAU | 44 | 2024 | 440001113 | geo | A | A | NaN | ... | NaN | 88.63 | 87.7 | 63.44 | NaN | 72.98 | NaN | 77.5 | 88.0 | NaN |
11207 | 910150085 | 1110 | GH LES CHEMINOTS SOINS DE SUITE | 91 | 2023 | 910150085 | geo | NaN | NaN | Données insuffisantes | ... | Données insuffisantes | NaN | NaN | NaN | Données insuffisantes | NaN | Données insuffisantes | NaN | NaN | Données insuffisantes |
1976 | 210987657 | 1102 | HOSPICES CIVILS DE BEAUNE | 21 | 2018 | 210987657 | geo | Données insuffisantes | B | NaN | ... | NaN | Données insuffisantes | Données insuffisantes | Données insuffisantes | NaN | Données insuffisantes | 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 | |
---|---|---|---|---|---|
10355 | 2021 | 830000345 | CHITS CH SAINTE MUSSE | 83 | 79.29 |
9600 | 2019 | 770000131 | CH DE COULOMMIERS | 77 | Non validé |
6278 | 2019 | 590000469 | CH FOURMIES | 59 | Données insuffisantes |
127 | 2023 | 020000394 | CH LAON | 02 | 78.65 |
5961 | 2023 | 570000059 | CH MARIE-MADELEINE DE FORBACH | 57 | 82.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