PerlMSI
présentation

blog

archives

références

copyrights

télécharger

contact

Le PMSI avec PERL et Postgres SQL et R et ...
Compiler les sources de la fonction de groupage sous MacOSX

Pour ceux qui préfèrent les systèmes Unix, le Mac offre beaucoup d'avantages, dont une certaine ubiquité et une bonne standardisation par rapport à d'autres solutions tout aussi correctes (voire plus !) sur un plan technique.

Le problème pour le PMSI est l'absence de logiciel dédiés... ce que la suite PerlMSI cherche bien sur à corriger, mais l'absence des logiciels ATIH reste génante.

Voici donc quelques instructions simple pour compiler la fonction de groupage sous un Mac OSX utilisant Snow Leopard, avec XCode installé :

  • enlever malloc.h de ccam10.c controle10.c erreurs10.c fg10c.c selecteu10.c dans le répertoire SRC/SRCV10/ ccam11.c controle11.c erreurs11.c fg11.c selecteu11.c dans le répertoire SRC/SRCV11/
  • enlever malloc.h de SRC/fgv10v11.c
  • créer avec textedit, smultron, vim ou autre un fichier Makefile dans le répertoire SourcesFGMCO11 contenant les commandes suivantes, en faisant attention de ne pas remplacer les tabulations par des espaces :
    CC=cc
    CFLAGS=-O2
    CFLAGS+= $(INC)
    # Attention : il faut avoir supprime les #include <malloc.h>
    LIBS=-lgmalloc
    main_INC=-ISRC/
    ctrlgenficum_INC=-ISRC_CTRLFICUM/
    fgv10_INC=-ISRC/SRCV10/
    fgv11_INC=-ISRC/SRCV11/
    INC=$(ctrlgenficum_INC) $(fgv10_INC) $(fgv11_INC) $(main_INC)
    main_DEPS=SRC/fgv10v11.h
    ctrlgenficum_DEPS=SRC_CTRLFICUM/ctrlgenficum.h
    fgv10_DEPS=SRCV10/ccam10.h SRC/SRCV10/fg10c.h SRC/SRCV10/rum10.h \
    SRC/SRCV10/controle10.h SRC/SRCV10/gestionUM10.h SRC/SRCV10/rumfmt10.h \
    SRC/SRCV10/erreurs10.h SRC/SRCV10/grpstruct10.h SRC/SRCV10/tables10.h
    fgv11_DEPS=SRC/SRCV11/ccam11.h SRC/SRCV11/fg11.h SRC/SRCV11/rum11.h \
    SRC/SRCV11/controle11.h SRC/SRCV11/gestionUM.h SRC/SRCV11/rumfmt11.h \
    SRC/SRCV11/erreurs11.h SRC/SRCV11/grpstruct11.h SRC/SRCV11/tables11.h 
    DEPS=$(ctrlgenficum_DEPS) $(fgv10_DEPS) $(fgv11_DEPS) $(main_DEPS)
    ctrlgenficum_main_OBJ=SRC_CTRLFICUM/ctrlgenficum.o
    fgv10_OBJ=SRC/SRCV10/ccam10.o SRC/SRCV10/erreurs10.o SRC/SRCV10/gestionUM10.o \
    SRC/SRCV10/controle10.o SRC/SRCV10/fg10c.o SRC/SRCV10/selecteu10.o
    fgv11_OBJ=SRC/SRCV11/ccam11.o SRC/SRCV11/erreurs11.o SRC/SRCV11/gestionUM.o \
    SRC/SRCV11/controle11.o SRC/SRCV11/fg11.o SRC/SRCV11/selecteu11.o
    main_OBJ=SRC/fgv10v11.o
    OBJ=$(ctrlgenficum_main_OBJ) $(fgv10_OBJ) $(fgv11_OBJ) $(main_OBJ)
    
    %.o: %.c $(DEPS)
    	$(CC) -c -I $(INC) -o $@ $< $(CFLAGS)
    
    fgv10v11: $(OBJ)
    	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
    
    ctrlgenficum_main: $(ctrlgenficum_main_OBJ)
    	$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
    
    clean:
    	rm -f fgv10v11  ctrlgenficum_main *.CKP *.ln *.BAK *.bak *.o core \
    errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut  "#"*
    
Lancer alors la commande « make » dans le répertoire SourcesFGMCO11 et vous aurez le binaire fgv10v11 !

Il s'utilise de la manière suivante : $ ./fgv10v11
syntaxe : ./fgv10v11 {nom du fichier RSS} {repertoire des tables finissant par '/'} {type d'etablissement 1:DGF 2:OQN} {nom complet du fichier d'autorisation d'UM}

Les tables sont dans le répertoire SourcesFGMCO11/TAB. Le fichier d'autorisation, aussi appelé « ficum », est à générer par vos soins.


Relier les RSA aux RSS

Il est souvent nécessaire de relier les RSA aux RSS, ne serait-ce que pour pouvoir croiser les information tarifaires plus riches dans les RSA (suppléments, etc) aux informations administratives plus riches dans les RSS (car non anonymisées !).

Pour celà, on peut soit passer par l'ANOHOSP, méthode complexe et surtout ne permettant pas de relier un RSA à des informations précises, soit préférer utiliser les « portes dérobées » laissées par l'ATIH dans GENRSA à destination des contrôles de sécurité sociale.

On vous l'a bien dit, vous devez conserver les fichier in.zip et out.zip pour les contrôles externes. Mais avez-vous regardé de prêt de qu'ils contiennent ?

Prenez-donc 5 minutes pour extraire le fichier out.zip, c'est à dire les RSA, et regarder le fichier tra.txt : vous allez y découvrir des informations très intéressantes... et notamment l'association numéro de RSS, numéro de RSA et IEP, en texte clair, suivi de la date et du GHM.

Le out.zip n'est donc pas si anonyme que ça : il contient l'IEP à partir duquel le contrôle pourra avoir lieu. Ce pourrait aussi être une vulnérabilité pour remonter à des informations nominatives à partir de données théoriquement « anonymisées » PMSI s'il était transmis par epop... une possibilité qu'il n'est pas possible d'écarter pour l'instant, à moins de vérifier dans le code source de epop ce qu'il transmet (je n'ai pas ce code source!).

Toutefois, pour nos opérations de croisements nécessaires à des calculs plus précis, c'est une aide : une fois le RSS chargé et le RSA chargé, utilisez-donc l'outil TRA2SQL pour avoir une base vous permettant de croiser RSS et RSA. Vos calculs seront bien plus simple... vous pourrez même vous passer du RSS : le RSA contient déjà la plupart des informations intéressantes, sauf les dates et l'identité du patient. Mais avec l'IEP, vous pouvez toujours consulter les bases administratives... et le problème est réglé.

 


 

À quoi bon chercher un format pivot ?

Après avoir eu plusieurs échanges avec des collègues qui cherchent à traiter des données PMSI, j'ai constaté un point qui revient fréquemment dans nos discussions : la « nécessité » d'un format pivot. La discussion tourne court, lorsque j'essaye de donner les raisons pour lesquelles on ne devrait pas s'occuper d'un format pivot. L'idée est bien engraînée - sans doute vu l'ubiquité et l'utilisé des formats pivots dans tous les autres domaines.

Mais pour commencer, les formats PMSI évoluent beaucoup - certes moins qu'il y a quelques années, mais malgré tout à un rythme soutenu. Pour beaucoup de défenseurs du « format pivot », la solution la plus simple est de considérer tous les champs ayant existé au moins une fois depuis le début de la T2A, et les rajouter à la queue-le-leu dans un format segmenté quelconque du genre CSV, ou alors en tant que colonnes dans une base SQL.

La difficulté de cette approche est qu'elle complexifie beaucoup la gestion des données, les anciens champs défunts depuis plusieurs années venant masquer la lisibilité des champs actuels en cours d'utilisation... et donc bien plus importants.

De plus, cette approche conservatrice ne segmente pas les données par intérêt. Soyons franc - tous les champs n'ont pas le même intérêt. Pour des données anciennes, conserver les dates de mutation des patients, les UF correspondantes, les diagnostics reçus (séparés par type: DP, DR, DAS, DAD), les actes pratiques (avec leur date, phase, extension...) suffit à répondre à la plupart des interrogation sur l'activité des services et leur évolution.

Cette approche minimaliste m'a guidée vers une approche orientée objet : oui à la complexité liée au champs désuets, si elle est encapsulée par des méthodes d'abtraction qui permettent de ne pas avoir à s'en soucier ! Cette épiphanie m'a fait cesser le développement de scripts gérant un ensemble de formats pour intégrer leurs fonctions de manière différente, « orientée objet ». Il s'agit de l'approche retenue dans la bibliothèque PerlMSI : un objet RSS est créé à partir d'un fichier. Il est possible d'accéder à son contenu sous forme de colonne pour faire sa propre cuisine, ou de se contenter des fonctions d'accès (bien sur, il aurait été possible d'obtenir un résultat proche en conservant les scripts existants et en se recentrant sur des fonctions plsql, mais la lourdeur imposée par les bases SQL devenait de plus génante, et m'a conduit à les considérer comme une simple sortie potentielle pour des manipulations spécifiques, et non le passage imposé du traitement de données).

Les abstractions sont préférables pour leur simplicité, mais surtout car elles laissent l'interprétation des différences de format à l'implémenteur. Par exemple, un fichier RSS de 2004 ne renseignait pas l'IEP correspondant à un RSS. Un objet RSS créé à partir d'un fichier RSS de 2004 ne sait donc pas lister les IEP distincts qu'il contient, alors que ce même objet créé par un fichier RSS plus récent aura cette possibilité. Toutefois, si l'objet RSS de 2004 peut acquérir cette information, par exemple en le croisant à un autre objet créé à partir d'un autre fichier, cette possibilité et les calculs qui vont avec sera offerte.

À mon avis, il s'agit de la bonne approche, car elle permet de laisser le choix de la complexité à l'implémenteur des méthodes de ces objets : si tel champ (ex: IEP) a une importance suffisante, une méthode supplémentaire pour gérer les cas où l'absence de champs pose problème sera proposée. Si le champs est très secondaire et désuet, aucun besoin de perdre du temps à implémenter une méthode qui sera utilisée par un faible pourcentage des utilisateurs. Ces derniers pourront toujours accéder au contenu intégral de l'objet pour faire leur propre cuisine. La loi du marché à l'oeuvre...

C'est un peu de cette manière que je vois le format pivot : inutile voire dangereux, car obligeant de gérer de très rares recettes de cuisine au détriment des cas d'utilisation les plus fréquents. Une approche objet laisse suffisamment de souplesse pour traiter de manière différente les besoins les plus fréquents, de ceux les plus rares.