Posts Tagged ‘call symputx’

h1

Répéter une action sur plusieurs variables avec le langage macro

août 13, 2008

Sous SAS, deux possibilités sont envisageables pour répéter une action sur plusieurs variables. Dans le cas d’un data step, la syntaxe de l’ARRAY est tout à fait appropriée. Dans d’autres cas, le langage macro peut s’avérer plus pertinent. Voici donc une présentation de l’approche via le langage macro.

1. L’exemple

Pour illustrer le propos, le programme aura pour but de définir un PROC REPORT contenant toutes les variables du data set SASHELP.CLASS. Si on connaît le nom des variables, la syntaxe se résume de la manière suivante.

proc report data=sashelp.class;
   columns name age sex weight height;
   define name   / display;
   define age    / display;
   define sex    / display;
   define weight / display;
   define height / display;
run;

Mais si on ne connaît pas le nom des variables par avance, il faut automatiser la tâche.

2. Remplacer le nom des variables par des macros variables

Dans l’exemple suivant, le nom de chaque variable est sauvegardé dans une macro variable. Ces macros variables ont une structure particulière :

un préfixe commun + un nombre

%let class1 = name;
%let class2 = age;
%let class3 = sex;
%let class4 = weight;
%let class5 = height;

proc report data=sashelp.class;
   columns name age sex weight height;
   define &class1. / display;
   define &class2. / display;
   define &class3. / display;
   define &class4. / display;
   define &class5. / display;
run;

3. Répéter l’instruction DEFINE grâce à une boucle

Grâce à cette structure particulière, une boucle peut être envisagée. L’instruction DEFINE est alors répétée autant de fois qu’il y a de variables. La boucle est définie par une macro variable « I » qui prend des valeurs allant de 1 à 5. La partie nombre de la macro variable est donc remplacée par la valeur de la macro variable « I ».

NOTE : Pour résoudre la macro variable lors de la première boucle, SAS effectue deux lectures. A la première lecture, les deux perluètes (ampersand) && se transforment en un seul ; &i. se transforme en 1. On a donc &CLASS1. A la deuxième lecture, SAS résout la macro variable &CLASS1. comme précédemment.

%macro test;
   proc report data=sashelp.class;
   columns name age sex weight height;
   %do i=1 %to 5
      define &&class&i. / display;
   %end;
   run;
%mend test;
%test;

4. Créer les macros variables de manière automatique

Pour créer les macros variables automatiquement, il faut agir en deux étapes.

  1. Enregistrer chacune des noms de variables du data set choisi dans PROC REPORT (SASHELP.CLASS) dans un nouveau data set (LST_VAR) et plus particulière dans une variable (NAME).
  2. Associer un numéro à chaque nom de variable (compteur) et convertir l’information en macro variable (CALL SYMPUT).

proc sql;
   create table lst_var as
      select name
      from dictionary.columns
      where upcase(libname)=‘SASHELP’ and
            upcase(memname)=‘CLASS’;
quit;

data _null_;
   set lst_var;
   cnt+1;
   call symput (cats(‘CLASS’,put(cnt,best.)),name);
run;

5. Compter le nombre de variables de manière automatique

Si le nombre de variable dans le data set n’est pas connu à l’avance, il faut le retrouver. Cette information est ensuite sauvegardée dans une macro variable, disons MAX_VAR, et remplacera notre nombre 5. L’article « 3 méthodes pour construire des macro variables sans macro » vous donnera plus de précisions concernant la création d’une macro variable.

Obtenir rapidement le nombre de variables dans un data set : Un moyen pour trouver le nombre de variables est de faire appel au dictionnaire de SAS intitulé TABLES.

proc sql noprint;
   select nvar into : max_var
   from dictionary.tables
   where upcase(libname)=‘SASHELP’ and
         upcase(memname)=‘CLASS’;
quit;

Plus de flexibilité sur la liste des variables concernées : Un autre moyen pour compter le nombre de variables est d’agir en deux étapes.

  • Enregistrer dans un variable d’un nouveau data set chacune des noms de variables de SASHELP.CLASS.
  • Compter le nombre d’observations dans ce data set. Vous pouvez vous reporter à l’article « Combien d’observations dans mon data set » pour plus de précisions sur les différentes alternatives.

Dans notre exemple, il s’agit de créer le data set LST_VAR pour la première étape. Le code de la section 4 est tout à fait suffisant pour cela. Ensuite, CALL SYMPUTX peut servir à sauvegarder l’information dans une macro variable.

data _null_ ;
   call symputx(‘max_var’,_N_-1);
   set lst_var;
run;

Pourquoi vous ai-je proposé cette alternative ?  Ici, toutes les variables sont sélectionnées. Mais si seulement quelques une sont choisies, seule la seconde alternative marche. Voici quelques sous-sélections possibles.

  • Sélectionner toutes les variables numériques,
  • Sélectionner toutes les variables finissant pas _X,
  • etc.

En résumé : En résumé, le code se décompose en 2 étapes : créer les macros variables et utiliser ces macros variables pour définir une boucle.

*1. Créer les macros variables CLASS1 à CLASS5, MAX_VAR.;

*1.1 Créer le data set LST_VAR servant de fichier de référence.;

proc sql;
   create table lst_var as
      select name
      from dictionary.columns
      where upcase(libname)=‘SASHELP’ and
            upcase(memname)=‘CLASS’;
quit;

*1.2 Créer les macro variables CLASS1-CLASS5 en se basant sur le data set LST_VAR créé précédemment.;

data _null_;
   set lst_var;
   cnt+1;
   call symput (cats(‘CLASS’,put(cnt,best.)),name);
run;

*1.3 Créer la macro variable VAR_MAX en se basant sur le data set LST_VAR créé précédemment.;

data _null_ ;
   call symputx(‘max_var’,_N_-1);
   set lst_var;
run;

*2. Reporting : appeler les différentes macro variables pour créer la boucle autour de l’instruction DEFINE.;

%macro test;
proc report data=sashelp.class;
   columns name age sex weight height;
   %do i=1 %to &max_var.;
      define &&class&i. / display;
   %end;
run;
%mend test;
%test;

h1

3 méthodes pour construire des macros variables sans macro

février 7, 2008

Les macro-variables peuvent être créées soit à l’intérieur d’une macro, soit à l’extérieur. Ici je vous propose de voir comment les créer indépendamment d’une macro. Pour une valeur brute indépendante du reste de votre programme, je vous propose le statement %let. Pour des macros variables définies à partir d’autres informations disponibles dans un jeu de données, vous aurez le choix entre le statement ‘CALL SYMPUT’ dans un data step et le mot clé ‘INTO :’ dans une procédure SQL.

1. Assigner une valeur manuellement : L’instruction %LET sert à définir une macro variable quand vous connaissez la valeur à donner à votre macro variable à l’avance et qu’elle n’est pas fonction de vos données. Tapez la valeur de votre macro-variable. Pour chaque %LET statement une macro variable est créée. Faites suivre %LET du nom de la variable et saisissez sa valeur après le signe égal.

%let projet=53269 ;

2. Créer une macro variable dans un data step : pourquoi vouloir passez par un data step ? Voici deux exemples : assigner la valeur d’une variable automatique comme _N_ ; créer une boucle pour créer autant de macros variables qu’il y a de valeurs distinctes dans une variable.

2.1 La distinction entre CALL SYMPUT et CALL SYMPUTX : les arguments de CALL SYMPUT sont le nom de la macro variable dans un premier temps, et sa valeur dans un second temps. Jusqu’à SAS 8.2, on devait convertir les valeurs numériques en valeur caractères, via la fonction PUT, pour créer la macro variable. Depuis SAS 9, on peut directement utiliser la valeur numérique avec CALL SYMPUTX.

data _null_ ;
   set demo;
   call symputx(‘Nb_boucle’,_N_);
run;

Pourquoi cette nouveauté si tardive ? Parce que la valeur d’une macro variable est toujours caractère. Dans un macro statement tel %if…, vous aurez besoin d’une macro fonction pour faire la somme de deux macro variables. En dehors, vous devrez écrire la macro variable entre double guillemets.

2.2 Un seul CALL SYMPUT(X) et plusieurs macros variables : si vous avez un jeu de données avec deux variables : une contenant le nom de vos futures macro-variables et l’autre leur valeur, vous pouvez avec un seul CALL SYMPUT/SYMPUTX créer toutes les macro-variables. Pour cela, il vous suffit de mettre le nom des deux variables dans les paramètres. Cette fois-ci il n’y a plus de guillemets.

Niveau Dose
Dose1 50
Dose2 100
Dose3 150
call symputx (niveau,dose);

3. Créer une macro variable dans une procédure SQL : Vous pouvez répondre à trois besoins avec PROC SQL : 1) sauvegarder une valeur unique dans une macro variable, comme le nombre total d’observations dans un jeu de données ; 2) sauvegarder toutes les valeurs prises par une variable dans une seule macro variable, en jouant avec SEPARATED BY. 3) créer autant de macro variable qu’il y a de valeurs sélectionnées.

3.1 Une macro variable ayant une seule valeur : pour sauvegarder le nombre d’observations d’un data set dans une variable CNT, vous écririez select count(*) as cnt from demo ; Pour sauvegarder cette information dans une macro variable CNT vous remplacerez ‘AS’ par ‘INTO :’

proc sql;
   select count(*) into : cnt
      from sashelp.class ;
quit;

3.3 Plusieurs macros variables à partir de plusieurs valeurs: la syntaxe suivante permet de créer plusieurs macros variables à partir de plusieurs calculs extraits d’un même data set.

proc sql;
   select distinct count(age), count(*)
              into : cnt_age,
                   : cnt_rec
       from sashelp.class;  
quit;

Si les noms de variables ont un nom schématique (base + nombre incrémenté par 1), la syntaxe suivante peut être appliquée.

proc sql;
   select distinct age into : pop1-:pop6
      from sashelp.class;
quit;

3.4 Plusieurs valeurs dans une seule macro variable: vous pouvez aussi décider de sauvegarder ces cinq valeurs dans une seule macro variable. Ne listez alors qu’un nom. Au moment d’appeler votre macro vous observerez que seule la première valeur apparaît si vous n’avez pas précisez un délimiteur comme un espace ou une virgule entre les observations via SEPARATED BY. Par défaut, le délimiteur est en effet un passage à la ligne. Voici deux exemples :

proc sql;
   select distinct age into : age_space
                            separated by ‘ ‘
      from sashelp.class;
   select distinct age into : age_comma
                           separated by ‘,’
      from sashelp.class;
quit;

 
3.5 La macro variable automatique SQLOBS : Enfin sachez qu’il existe une macro variable automatique SQLOBS qui sauvegarde le nombre d’observation de la dernière procédure SQL. Cette fonction peut s’avérer pratique à condition de bien garder à l’esprit qu’il ne faudra pas par la suite intercaler d’autres SQL statement qui changeraient la valeur de cette macro variable automatique.

3.6 Extra

L’option NOPRINT : Par défaut, les valeurs d’un select statement sont affichées dans la log, si aucun jeu de données n’est crée. Si vous ne souhaitez pas voir la valeur des macros variables s’afficher dans votre log arrêter via l’option NOPRINT :

   proc sql noprint;
      *ma sélection;
   quit;

Important: si aucun record n’est sélectionné avec la PROC SQL, la macro variable n’est pas créée. Dans l’exemple ci-dessous, la macro variable MAX_AGE n’apparaît pas dans la liste des variables de l’utilisateur disponible dans la log.

proc sql noprint;
   select max(age) into : max_age
   from sashelp.class
   where age > 18;
quit;

%put _user_;

4. Supprimer une macro variable globale

Les macros variables globales sont disponibles tout le long de la session. On peut choisir d’écraser la valeur en créant une nouvelle macro variable portant le même nom ou choisir de la supprimer. Dans la version 9.1.3, l’instruction globale %SYMDEL fait supprime les macros variables globales pour vous. Pour ce qui est des variables locales, il n’y a pas d’instructions pour la simple raison que la valeur de la macro variable ne peut pas être rappelée en dehors de la macro.

%symdel cnt cnt_age cnt_rec pop1 pop2 pop3 pop4 pop5 pop6 age_space age_comma;

NOTE : Pour définir une condition basée sur une macro variable, il faut qu’elle existe. Si une macro variable n’est pas créée, faute de valeur à assigner, il est conseillé de définir au préalable une valeur par défaut avec un %LET par exemple. Elle pourra ensuite être actualisée par une des trois méthodes mentionnées ci-dessus. Une autre solution est de s’assurer de l’existence de la macro variable avec la fonction %SYMEXIST.