Annonce

Bienvenue sur le site support de mes ouvrages d'introduction à SAS

La 4ème édition de mon ouvrage est disponible depuis le 11 avril 2019 !

Où trouver cet ouvrage ?


#1 18-12-2019 08:16:58

SAS-SR
Administrateur
Lieu: Université d'Orléans
Date d'inscription: 01-09-2008
Site web

Renommer des variables (partie 2)

Bonjour

Pourquoi partie 2 ?

Parce qu'il y a déjà eu une partie 1 (voir ce sujet des beaux mercredis) et qu'il s'agit en fait d'une problématique récurrente...

Alors voilà :

vous disposez dans une table, parmi d'autres variables, d'un ensemble de variables (on n'en connait pas le nombre) dont le nom débute systématiquement par XYZ. Votre objectif est de renommer toutes ces variables en X1, X2, X3...

voici la table sur laquelle vous allez pouvoir tester vos programmes :

Code:

data test;
input  ident $ Z1 XYZ104 XYZ108 XYZ112 XYZ114 XYZ122 dummy1 dummy2 dummy3;
datalines;
abcd 111 0 1 0 1 0 1 0 1
defg 222 1 0 0 0 1 1 0 1
hijk 333 0 1 0 1 0 0 1 1
lmno 444 1 0 0 0 1 0 1 1
pqrs 555 0 0 0 1 0 1 0 1
tuvw 666 0 1 0 0 1 1 0 1
run;

il y a ici 5 variables XYZ mais le programme que vous devez rédiger doit fonctionner, sans aucune modification, avec des tables contenant un autre nombre de variables XYZ...

Nous allons au cours des prochaines semaines (on va quand même laisser passer les vacances de fin d'année avant de nous attaquer à la présentation des solutions), examiner plusieurs programmes menant au résultat souhaité. Notre idée sera de présenter le programme le plus efficace possible (i.e. qui utilisera le moins de ressources) et nous commencerons par présenter le programme qui certainement utilise le plus de ressources...

amusez vous dès à présent à rédiger vos propres programmes et rendez vous en 2020 !

Hors ligne

 

#2 08-01-2020 09:45:14

SAS-SR
Administrateur
Lieu: Université d'Orléans
Date d'inscription: 01-09-2008
Site web

Re: Renommer des variables (partie 2)

Bonjour

et mes meilleurs vœux pour cette année 2020 ! Qu'elle vous apporte beaucoup de programmes SAS amusants !

J'espère que vos vacances (si vous en avez eues) vous ont été profitables et qu'elle vous ont donné le temps de réfléchir à mon petit problème...

Cette semaine, je vous présenterai deux solutions possibles, avec des variantes, pour renommer nos variables.

La première solution est notoirement inefficace mais il est toujours intéressant de comprendre dans quel cas un programme mobilise trop de ressources afin d’être inciter à réfléchir autrement…

Ce premier programme est en deux étapes – voici la première :

Code:

data _null_;
   set test(obs=1);
   array lesxyz{*} xyz: ;
   call symputx("nvar",dim(lesxyz));
run;

Ce premier programme a pour objectif de créer une macro-variable dans laquelle on stocke le nombre de variables XYZ. On aurait pu construire cette macro-variable en passant par les tables dictionnaires…

Le programme devient alors :

Code:

proc sql noprint ;
   select count(*) into :nvar2 
      from dictionary.columns 
      where libname="WORK" and memname="TEST" and name like "XYZ%";
quit;

Il faudrait en faire le test mais j’ai dans l’idée que mon étape data _null_ doit être plus rapide lorsque qu’on a une table de grande dimension…

Bref…

Que faire avec cette macro-variable ? L’utiliser…

Code:

data test2(drop=xyz:);
   set test;
   array lesxyz{*} xyz: ;
   array x{&nvar};
   do i=1 to &nvar;
      x{i}=lesxyz{i};
   end;
run;

Ce programme est TRES mauvais : votre objectif est uniquement de renommer vos variables, sans aucune modifications des modalités. Pour cela, vous allez faire transiter toutes vos observations dans le PDV !

Vous construisez, de plus, une seconde table (puisqu’une étape DATA TEST / SET TEST n’est pas vraiment conseillée même si elle est possible) qui encombrera votre disque dur…

Si votre table est de taille conséquente, évidemment, ça risque de prendre un certain temps et prendre une certaine place sur votre disque dur…

A titre d’exemple, reprenez l’exercice 5.1 (ED4). Construisez la table décrite en appelant vos variables X1-X200. Au moyen de la programmation présentée ici, renommez les variables en Y1-Y200 et regardez le temps que cela va vous prendra…

Programmation alternative (et plus efficace), toujours en deux étapes :

Code:

data _null_ ; 
   set sashelp.vcolumn (where=(libname="WORK" and memname="TEST" and name like "XYZ%")) end=last;
   call symputx(compress("remp"||_n_),cats(name,"=","X",_n_));
   if last then call symputx("nbremp",_n_);
run;

La première étape a pour objectif de construire un ensemble de macro-variables REMPx (autant de macro-variables que vous allez avoir de variables à renommer). Ces macro-variables vont avoir pour valeurs  XYZ104=X1, XYZ108=X2 etc. Nous stockons aussi dans une macro-variable NBREMP le nombre de remplacements à effectuer (ici, 5).

Dans la seconde étape, nous allons bien entendu utiliser ces macro-variables au sein d’un macro-programme

Code:

%macro toto;
proc datasets nolist;
   modify test; 
      rename
      %do i=1 %to &nbremp;
      &&remp&i 
      %end;
;
quit;
%mend;

%toto

Et vous constaterez que vos variables ont bien été renommées.

Afin de voir le gain de temps associé à cette seconde méthode, reconstruisez la table de l’exercice 5.1 et renommez les variables X1-X200 en Y1-Y200.

A priori, il n’y a pas photo…

Vous me direz « a-t-on vraiment besoin d’un macro-programme pour effectuer cette tâche ? » oui si vous avez plusieurs macro-variables à résoudre : vous devez passer par une boucle %do qui n’est possible qu’à l’intérieur d’un macro-programme.

Vous pouvez éviter le passage par un macro-programme si vous réussissez à stocker tous vos changements de noms dans une seule macro variable…

Je vous laisse y réfléchir pour la semaine prochaine… tout comme je vous laisse réfléchir à ma dernière solution qui effectuera ces changements de noms en une seule et unique étape data _null_...

Mathieu, lecteur assidu des beaux mercredis a déjà trouvé cette seconde solution..

à la semaine prochaine...

Hors ligne

 

#3 16-01-2020 08:01:19

SAS-SR
Administrateur
Lieu: Université d'Orléans
Date d'inscription: 01-09-2008
Site web

Re: Renommer des variables (partie 2)

Concluons ce sujet :

Si vous voulez stocker tous vos changements de noms dans une unique macro-variable, vous pouvez exécuter ce programme :

Code:

data _null_ ; 
   set sashelp.vcolumn (where=(libname="WORK" and memname="TEST" and name like "XYZ%")) end=last;
   length lamac $ 32000 ;
   retain lamac ;
   lamac=catx(" ",lamac,cats(name,"=","X",_n_));
   if last then call symputx("lesremp",lamac);
run;

proc datasets nolist ;
   modify test;
      rename &lesremp ;
quit;

c'est en fait un peu "dangereux..." : nous avons besoin dans notre étape data _null_ d'une variable temporaire appelée ici LAMAC qui va, observation après observation, stocker les divers remplacements à faire. Cette macro-variable, il faut lui donner une longueur suffisante pour permettre le stockage de tous les remplacements.

Dans le cadre qui est le notre, 32000 est largement suffisant mais dans un cadre "réel", avec des données "réelles", il est tout à fait possible que vous ayez à renommer de centaines voire des milliers de variables. Une longueur de 32000 pourrait donc ne pas être suffisante...

L'approche proposée ici est donc risquée (et puisqu'elle est risquée... autant éviter...)

Bon... ai-je une autre approche, moins risquée et plus efficace à proposer ?

bien entendu !

Code:

data _null_ ; 
   set sashelp.vcolumn (where=(libname="WORK" and memname="TEST" and name like "XYZ%")) end=last;
   if _n_=1 then call execute("Proc datasets nolist ; modify test ; rename");
   call execute (cats(name,"=X",_n_));
   if last then call execute (";quit;");
run;

l
e secret ? CALL EXECUTE !

bon... comme je n'en parle pas dans mon ouvrage, il faut que je vous fasse un petit topo...

dans le programme proposé, notre étape DATA _NULL_ va "rédiger" au moyen de CALL EXECUTE, un programme qui sera exécuté après l'exécution de l'étape DATA.

Déjà, notons que l'instruction SET utilise un extrait de la vue SASHELP.VCOLUMN réduite aux informations relatives à notre table TEST et aux variables dont le nom débute par XYZ.

Code:

if _n_=1 then call execute("Proc datasets nolist ; modify test ; rename");

à la première exécution du programme (if _n_=1), les instructions qui débutent notre PROC DATASETS sont stockées pour exécution ultérieure.

L'instruction qui suit est ensuite va permettre "d'écrire" les instructions de type "ancien nom de la variable" (information stockée dans la variable NAME) = X auquel on concatène le numéro de l'exécution :

Code:

cats(name,"=X",_n_)

lorsque dans le PDV sera traité la dernière observation de la table (qui n'est pas une table mais une vue et qui, en tant que vue ne contient pas d'observation... je sais... mais soyons précis...), l'instruction de clôture de notre PROC DATASETS est écrite : ;QUIT ;

Demandez l'exécution du programme et regardez votre journal :

Code:

NOTE: CALL EXECUTE generated line.
1   + Proc datasets nolist ; modify test ;
1   +                                      rename
2   + XYZ104=X1
3   + XYZ108=X2
4   + XYZ112=X3
5   + XYZ114=X4
6   + XYZ122=X5
7   + ;
NOTE: Renaming variable XYZ104 to X1.
NOTE: Renaming variable XYZ108 to X2.
NOTE: Renaming variable XYZ112 to X3.
NOTE: Renaming variable XYZ114 to X4.
NOTE: Renaming variable XYZ122 to X5.
7   +  quit;

et vous avez renommé vos variables !

amusant, non ?

ce sujet est maintenant terminé. A la semaine prochaine pour un nouveau sujet des beaux mercredis

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB
Traduction par FluxBB.fr
Flux RSS