Posts Tagged ‘%put’

h1

La 3ème méthode qui fait la différence pour sélectionner en se basant sur une second data set

février 16, 2009

Suite au précieux conseil d’Arnaud Gaborit (A.I.D.), je vous propose de compléter l’article du 26 janvier dernier intitulé « Deux méthodes pour sélectionner en se basant sur une second data set« . Les personnes travaillant sur de grosses bases de données apprécieront.

Lectures complémentaires :

1. Rappel : les données et le résultat attendu

D’un côté, on a un data set contenant la liste des effets secondaires observés. Il y a une ligne par effet secondaire. Seuls les patients ayant eu un effet secondaire sont enregistrés.

data ae_multi;
   input patref ae_id;
   datalines;
1 1
1 2
2 1
4 1
4 2
5 1
;
run;

De l’autre côté, on a la liste des patients correspondant à la population qui nous intéresse. Une ligne correspond à un patient.

data pat_uniq;
   input patref;
   datalines;
2
3
4
;
run;

Le but est de garder uniquement les effets secondaires des patients présents dans notre population.

patref ae_id

   2     1
   4     1
   4     2

2. Créer un format à partir d’un data set

Dans une premier temps, un format numérique (TYPE=N est la valeur par défaut) appelé PATREF (FMTNAME=’PATREF’) est créé à partir du data set sur les patients. La variable PATREF sert de valeur START. Pour toutes les valeurs de START, on applique le même libellé (LABEL=’retenir’).

Si le data set contient plusieurs variables (ce qui sera généralement le case), l’option KEEP servira à limiter la sélection à la variable servant à définir START.

data pat (keep=start fmtname label);
   set pat_uniq (rename=(patref=start)); *(keep=patref);
   fmtname='PATREF';
   label='retenir';
run;

Si plusieurs valeurs identiques pour la variable START sont présentes dans votre fichier, vous devrez supprimer les doublons. L’étape suivante ne marchera pas sinon.

*proc sort data=pat nodupkey;
*by start;
*run;

Le data set est à présent convertit en format au moyen de l’option CNTLIN. Ce format est sauvegardé par défaut dans le catalogue FORMATS de la bibliothèque WORK.

proc format cntlin=pat;
run;

3. Sélectionner les observations de son choix

Ici, l’option WHERE est privilégiée à l’instruction IF pour des raisons de performance.

Ensuite, grâce à la fonction PUT, les valeurs de PATREF sont converties en RETENIR si elles sont présentes dans le data set PAT_UNIQ. Seules ces valeurs RETENIR sont gardées.

data ae_multi;
   set ae_multi (where=(put(patref,patref.) = 'retenir'));
run;

Voir le résultat :

proc print data=ae_multi;
run;
h1

Créer un fichier .sas automatiquement

décembre 4, 2008

Il est très courant en SAS de créer un programme à partir d’une instruction FILENAME et d’une étape data. Souvent les informations contenues dans un fichier de référence servent à faire varier quelques lignes de code.

1. Le data set pour l’exemple

Dans cet exemple, il est demandé de renommer toutes les variables commençant pas z_ de manière automatique car le nom et le nombre de ces variables peut varier.

data lab;
   input patient z_test1 $ test1_val z_test2 $ test2_val;
   datalines;
1 TEMP 38 HR 80
;
run;

Si deux variables seulement seraient à renommer et si elles s’appelaient toujours Z_TEST1 et Z_TEST2, le code serait tout simplement.

data lab;
   set lab (rename=(z_test1=test1 z_test=test2));
run;

Ou

data lab;
   set lab;
   rename z_test1=test1
          z_test2=test2;
run;

Ou

data lab;
   set lab;
   rename z_test1=test1;
   rename z_test2=test2;
run;

C’est cette dernière forme qui nous intéressera de reproduire de manière automatique.

2. Créer le fichier de référence

La liste de toutes les variables commençant pas Z_ du data set temporaire LAB, est sauvegardée dans le data set REF et plus particulièrement dans la variable OLD_NAME. On choisit en plus d’ajouter une seconde variable NEW_NAME contenant les noms sans les Z_.

Dans notre exemple, vu qu’il y a 2 variables à renommer, le data set REF contient deux observations dans la variable NAME.

proc sql;
   create table ref as
      select name as old_name,
             subst(old_name,3) as new_name
      from dictionary.columns
      where upcase(libname)='WORK' and
            upcase(memname)='LAB' and
            upcase(name) like 'Z_%';
quit;

3. Créer un fichier .sas avec une instruction filename et une étape data

Dans un second temps, l’emplacement et le nom du programme SAS à créer sont à donner. C’est le rôle de l’instruction FILENAME. Pour y faire ensuite référence, il suffit d’utiliser le surnom donné dans l’instruction. Ici, il s’agit du surnom SASREF.

filename sasref 'C:/sasref/rename_z.sas';

Les instructions FILENAME et LIBNAME ont des similarités. Dans une instruction LIBNAME, le nom de la bibliothèque s’appelle le LIBREF. Ici on parle de FILEREF. Tous les deux (LIBREF et FILEREF) doivent avoir une longueur de 8 au maximum et ne doit pas commencer par un chiffre.

4. Une étape data

Dans un troisème temps, une étape data est donnée pour écrire le programme.

  1. Ne pas créer de data set, DATA  _NULL_ : Comme, il n’y a pas besoin de créer de data set, le nom du data set est remplacé par le mot _NULL_.
  2. Désigner le nom du fichier .sas à créer, FILE: Puis, on précise où les informations contenues dans lesinstructions PUT seront copiées.
  3. Lire les données du fichier de référence, SET : Après, il faut désigner notre data set REF contenant les observations dans l’instruction SET.
  4. Utiliser la variable automatique _N_=1 pour désigner la première boucle autour de l’étape data et donc ici la première observation : Lors de la lecture de la première observation du data set REF les instructions DATA LAB et SET LAB seront écrites dans le programme.
  5. Ajouter autant d’instruction RENAME que d’observations dans le ficihier REF : Pour chacune des observations de REF, une instruction RENAME sera écrite. Le contenu variera en fonctions des valeurs contenues dans les variables OLD_NAME et NEW_NAME.
  6. Utiliser l’option END= pour désigner la dernière observation du data set REF : Enfin à la lecture de la dernière observation, une instruction RUN est ajoutée. Pour désigner la dernière observation, on fait appel à l’option END= de l’instruction SET qui nous permet d’introduire une nouvelle variable nommée EOF. Celle variable prend la valeur 0 pour toutes les observations du data set REF sauf la dernière qui prend la valeur 1.
data _null_;
   file sasref;
   set ref end=eof;
   if _N_=1 then
      do;
         put 'data lab;';
         put '    set lab;';
      end;
   put '   rename '  old_name '=' new_name ' ;';
   if eof then put 'run;';
run;

5. Exécuter le programme

Pour terminer il est possible d’appeler le programme avec une instruction %INCLUDE et d’enlever le lien qui existe entre SASREF et le fichier (desassign the filename reference)

Appeler le programme :

%include sasref;

Couper le lien entre le FILEREF et le programme RENAME_Z.SAS :

filename sasref clear;

Pour vous entraîner, vous pouvez faire varier le code et essayer de retrouver les autres syntaxes pour renommer les variables citées en première partie.

h1

Afficher 7h30 du matin sous la forme 07:30

octobre 24, 2008

Les heures, minutes et secondes sont enregistrables sous SAS sous la forme d’un seul chiffre exprimant cette durée en seconde. On parle d’heure SAS (SAS time). A l’affichage, il y a le format TIME5. pour représenter les heures et les minutes uniquement à partir de 5 caractères au maximum. Mais ce format omet le zéro de début pour les heures à un chiffre comme 9h00. Voici donc dans cet article plusieurs solutions pour contourner le problème allant d’un format avec PICTURE, en passant par les fonctions RIGHT et TRANWORD.

1. Le data set servant d’exemple

Pour présenter les variantes, un data set NEWTIME est créé. Il contient une variable SEC avec 4 valeurs exprimant le temps en secondes et une valeur manquante.

  • 7h30 : prenons 7h30m00s ou 27000 secondes (7x60x60*60) pour exprimer 7h30 du matin
  • 15h : prenons maintenant 15h00m00s ou 54000 secondes pour obtenir 15h
  • 14h59 : pour désigner 14h59, des valeurs entre 14h59m00s (53940 sec) et 14h59m59s (53999 sec) sont possibles. Dans l’exemple, ces deux extrêmités sont choisies.
data newtime;
   input sec;
   datalines;
27000
54000
53940
53999
.
;
run;

2. Un format créé avec l’instruction PICTURE

La solution la plus flexible est probablement de créer un nouveau format. De cette manière, la valeur d’origine en seconde est encore disponible. Ce format peut aussi servir à convertir une variable caractère en heure SAS.

L’instruction PICTURE : Le format SASREF est construit à partir de l’instruction PICTURE dans une procédure PROC FORMAT. Le symbole %H réfère à des heures allant de 0h à 23h. Le symbole %M désigne des minutes allant de 0min à 59min. Le zéro intercalé ajoutera un zéro pour les valeurs inférieures à 10.

Documentation : Vous pouvez consulter la documentation en ligne pour connaître tous les symbole comme %M, %H disponible avec l’instruction PICTURE : PICTURE Statement.

proc format;
   picture sasref other='%0H:%0M' (datatype=time);
run;

Dans cet exemple, une variable caractère TIME_C est créée à partir de la fonction PUT et du format SASREF affichant 5 caractères.

Vous pouvez aussi exécuter l’instruction FORMAT pour appliquer le format SASREF5. à la variable SEC.

data newtime;
   set newtime;
   time_c=put(sec,sasref5.);
   *format sec sasref5.;
run;

3. Ajouter une condition pour traiter les valeurs manquantes

Une seconde variable TIME_C2 applique une contrainte particulière pour les valeurs manquantes. En effet, le format SASREF renvoie le mot ERROR si la valeur d’origine est manquante.

data newtime;
   set newtime;
   if not missing (sec) then time_c2=put(t1,sasref5.);
run;

4. Passer d’une valeur texte 7:30 à une valeur 07:30 avec les fonctions RIGHT et TRANWRD

Une troisième variable TIME_C3 est construite en deux étapes. Voyons donc l’interprétation faite pour une heure comme 7:30.

  • Fonction PUT et format TIME5 pour créer une valeur 7:30 : Tout d’abord, la fonction PUT combinée au format TIME5. crée une variable caractère de la forme 7:30 avec une longueur de 5. Par défaut, le texte est aligné à gauche. Le blanc est donc situé en 5ème position.
  • Fonctions RIGHT et TRANWORD pour ajouter un blanc en tête : Ensuite, une variable caractère 7:30 est convertie en 07:30, etc. Dans un premier temps, la fonction RIGHT aligne le texte à droite. Le blanc est en première position. Dans un second temps, la fonction TRANWRD remplace le blanc par un zéro.
data newtime;
   set newtime;
   if not missing (sec) 
   then time_c3=tranwrd(right(put(sec,time5.),' ','0');
run;

LA documentation en ligne propose une page sur les fonctions TRANWORD et RIGHT.

  • TRANWORD Function
  • RIGHT Function

Vous pouvez aussi consultez l’article sur la fonction PUT :

5. Aperçu des données

Voici un aperçu des différentes variables après :

sec     time_c time_c2 time_c3

27000   07:30   07:30   07:30
53940   14:59   14:59   14:59
53999   14:59   14:59   14:59
54000   15:00   15:00   15:00
    .   ERROR
h1

Un texte de 32 767 caractères passé au crible

septembre 1, 2008

La quantité d’espace alloué pour une observation dans un data set SAS peut aller jusqu’à 32 767 octets (byte en anglais). Pour m’amuser, j’ai voulu tester. Pour ce faire, j’ai procédé en trois étapes :

  • J’ai créé une variable de 32 767 caractères et j’ai imprimé sa seule valeur dans un fichier .TXT.
  • Puis, j’ai voulu voir comment se déroulait le passage de 32 767 caractères d’un fichier .TXT dans une seule observation d’un data set SAS.
  • Enfin, pour visualiser le tout, j’ai imprimé cette observation dans un fichier .RTF.

Note : La longueur (length) est le mot utilisé en SAS pour parler de la quantité d’espace alloué à une observation. Seules les variables de type caractères (character) peuvent avoir jusqu’à 32 767 octets. Les variables numériques en ont, en effet, 8 au maximum.  Un octet permet de stocker un caractère d’une variable texte. Pour plus de précisions sur l’octet, reportez-vous à l’article « 9 points autour de la notion d’octet« .

Note : La longueur allouée est identique pour toutes les observations d’une même variable. Si la longueur de la variable n’est pas explicitement donné, SAS utilise la longueur de la première observation. Avec un input file, seuls 8 octets sont attribués (SAS Online Doc. : SAS Variable Attributes »). 

data one;
   input x $;
   datalines;
ABC
ABCDEFGHIJKLMN
;
run;

data two;
   x=‘ABC’;
   output;
   x=‘ABCDEFGHIJKLMN’;
   output;
run;

data three;
x=‘ABCDEFGHIJKLMN’;
output;
x=‘ABC’;
output;
run;

Dans le premier exemple, la longueur sera de 8. La seconde observation sera donc coupée.

ABC
ABCDEFGH

Dans le second exemple, la longueur est définie par la première observation. Il s’agit donc d’une longueur de 3. La seconde observation est coupée et ne garde que les trois premiers caractères.

ABC
ABC

Dans le troisème exemple, la longueur est également définie par la première observation. Elle est donc cette fois de 14. Aucune des deux observations n’est coupée.

ABCDEFGHIJKLMN
ABCDEFGHIJKLMN

Cette valeur est changeable. Il s’agit de modifier l’attribut LENGTH d’une variable donnée dans un data step. La valeur est définie soit à l’instruction LENGTH, soit à l’instruction ATTRIB.

1. Imprimer 32 767 caractères dans un fichier .TXT

Dans l’exemple ci-dessous, un fichier .TXT est créé. Il contient 32 767 caractères venant d’une seule et même observation.

Une instruction LENGTH définissant le type et la longueur de la variable : Dans cet exemple, une variable TEST_VAR est créée. Il s’agit d’une variable caractère. Une longueur de 32 767 lui est assignée avec l’instruction LENGTH. Elle pourra donc contenir jusqu’à 32 767 octets par record.

Taper plus de 32 000 caractères, c’est long mais il y a la fonction REPEAT pour nous sauver : La valeur prise par le premier record de la variable TEST_VAR est donnée. J’ai choisi de répéter la lettre a 32 766 fois. Je dis bien 32 766 fois et non 32 765 fois car la fonction REPEAT ajoute à la valeur initiale ‘a’ 32 765 autres ‘a’, soit 32 765 + 1.

Ajouter un dernier caractère à notre valeur : A ces 32 766 lettres ‘a’, j’ai ajouté la lettre ‘b’ en faisant une concaténation grâce aux deux barres verticales. De cette manière, il sera possible de visualiser l’absence de coupure faite par SAS.

filename lgth_max ‘C:/sasref/lgth_max.txt’;
data _null_;
   file lgth_max;
   length test_var $ 32767;
   test_var=repeat(‘a’,32765)||‘b’;
   put test_var;
run;

filename lgth_max clear;

Ecrire le contenu de la variable dans un fichier externe : pour écrire les 32 767 caractères dans un fichier externe, SAS a besoin de trois instructions.

  • Ecrire du texte avec l’instruction PUT : L’instruction PUT est exécutée pour chaque observation de la variable TEST_VAR, c’est-à-dire une fois dans notre cas.
  • Diriger un texte vers une autre destination que la log avec l’instruction FILE : La valeur prise par la variable TEST_VAR est écrite dans un autre fichier. Cet autre fichier est désigné de manière indirecte dans l’instruction FILE. Je dis de manière indirecte car seul un nom figure dans l’instruction FILE, un nom désignant un fichier préalablement défini. On parle de FILEREF.
  • Caractériser un fichier de destination avec l’instruction FILENAME : Le FILEREF désignant la destination du texte à imprimer est défini dans l’instruction FILENAME. A la fin du programme, ce nom servant d’intermédiaire est supprimé pour pouvoir resservir et ainsi désigner un autre fichier ou chemin d’accès.

Pas besoin de créer un data set SAS ici : Dans le cas présent, nous avons besoin d’une étape DATA pour exécuter ce code mais nous n’avons pas besoin de créer un data set. Pour épargner la tâche de création d’un data set, le nom _NULL_ remplace le nom d’un data set.

2. Créer un data set SAS

Lire les données contenues dans un fichier externe : Une variable TEST_NEW est créée dans un data set nommé TEST_DS. Elle est de type caractère comme l’indique le symbole dollar ($) présent dans l’instruction INPUT.

Avant d’entrer une valeur dans cette variable, la longueur maximale autorisée est définie dans l’instruction LENGTH. Comme il s’agit d’une variable caractère, il faut ajouter le dollar.

Au lieu de saisir manuellement les valeurs dans le data step en introduisant le mot DATALINES, une instruction INFILE désigne le fichier où sont stockées les données.

data test_ds;
   infile ‘C:/sasref/lgth_max.txt’;
   length test_new $ 32767;
   input test_new $;
run;

Vérifier la valeur prise par l’attribut LENGTH de la variable TEST_NEW :  La procédure PROC CONTENTS donnera un aperçu des caractéristiques des variables du data set TEST. Bref, cette procédure donnera accès aux méta données (metadata ou données sur les données). Cela comprend la longueur allouée à la variable TEST_NEW et le type de la variable (caractère dans ce cas précis).

proc contents data=test_ds;
run;

3. Visualiser le data set dans un fichier .RTF

Seuls les 128 premiers caractères sont imprimables dans la fenêtre OUTPUT. Par contre, vous pouvez envisager d’autres destinations comme un fichier .RTF. Dans l’exemple, on joue avec les instructions ODS (Output Delivery System).

  • D’une part, la redirection vers la fenêtre output est stoppée le temps de l’impression, via les instructions ODS LISTING.
  • D’autre part, les 32 767 caractères sont envoyés dans un fichier .RTF grâce aux instructions ODS RTF.

ods listing close;
ods rtf file=‘C:/sasref/lgth_max.rtf’;
proc print data=test_ds;
run;
ods rtf close;
ods listing;

Pours les curieux : Changez la longueur pour 32 768 et expérimentez en direct les limites de SAS.

h1

Quand compilation et exécution font la différence, un exemple

août 21, 2008

SAS effectue plusieurs lectures d’un programme. A la première lecture, c’est la compilation. A la seconde, c’est l’exécution. Connaître ces notions vous aidera à comprendre les exemples ci-dessous : pourquoi le premier code proposé ne fonctionne pas alors que les autres passent. Les fonctions PUT, VVALUE, le dictionnaire DICTIONARY.COLUMNS et le DATA _NULL_ serviront dans les exemples.

1. Un premier exemple avec la fonction PUT

Rappel sur la fonction PUT : Une fonction PUT permet de convertir une variable numérique en variable texte ou une variable texte en une autre variable texte. Elle est composée de deux paramètres. D’un côté, il y a la variable d’origine. De l’autre côté, il y a le format à appliquer sur cette variable d’origine. C’est donc la valeur sous forme formatée qui devient une valeur texte. Reportez vous à l’article « Convertir une variable caractère en numérique et inversement » pour plus de détails.

La phase de compilation : A la compilation, SAS  vérifie que la variable d’origine et le format associé sont tous les deux du même type. Il faut qu’une variable numérique est un format qui s’applique à une variable numérique. De manière identique, il faut un format caractère pour une variable texte.

La phase d’exécution : Si on ne connaît pas à l’avance le type de la variable, on peut avoir envie de définir une condition : si la variable est numérique applique tel format, sinon applique tel autre format. Hors une condition IF/THEN n’est visible par SAS qu’à la phase d’exécution.

En d’autres termes, SAS tentera d’appliquer un format numérique à une variable numérique avant de regarder si la fonction PUT est définie dans une condition.

data import_excel;
   retain type ‘CHAR’;
   study = ‘999’;
   output;
   study = ‘888’;
   output;
run;

data study_new;
   set import_excel;
   if type=‘NUM’ then study_new=put(study,best.);
   else study_new=study;
run;

Le résultat : Dans l’exemple, un format numérique (BEST.) est appliqué à une variable texte (STUDY). La première partie de la condition ne s’applique pas car le type de la variable n’est pas égal à NUM. Mais SAS cherche un format $BEST. qui n’existe pas. Il est obligé de s’arrêter là.

28 data study_new;
29 set ref;
30 if upcase(type)=’NUM’ then study_new=put(study,best.);
                                                  —–
                                                  48

ERROR 48-59: The format $BEST was not found or could not be loaded.

31 else study_new=study;
32 run;

NOTE: The SAS System stopped processing this step because of errors.
WARNING: The data set WORK.STUDY_NEW may be incomplete.
When this step was stopped there were 0 observations and 3 variables
.

Un exemple où le type de la variable est inconnu : en important un fichier EXCEL (PROC IMPORT/MIXED=YES), le type de la variable sous SAS peut-être inconnu. La variable sera caractère si une cellule contient du texte. Sinon, elle sera numérique.

2. Une solution rapide

Une fonction Vxxx: la fonction VVALUE retourne une valeur texte. Elle utilise le format associé à la variable en interne pour construire la valeur sous forme formatée. La nouvelle variable aura une longueur de 200.

data study_new;
   set ref;
   if type=’NUM’ then study_new=vvalue(study);
   else study_new=study;
run;

3. Une solution plus lourde mais pouvant s’appliquer à plusieurs variables

Une autre solution est de générer le code à exécuter. Si la variable est numérique, c’est l’instruction avec PUT qui apparaîtra, sinon c’est l’autre instruction. Cette approche fait appel à la notion de dictionnaire et de DATA _NULL_.

3.1 Créer un data set contenant le nom des variables et leur type à partir du dictionnaire (dictionary) appelé COLUMNS

La première étape consiste à créer un data set, nommé DICT_REF, contenant la variable STUDY et son type.

Choix du dictionnaire : Le dictionnaire (dictionary) COLUMNS est un data set de référence, créé de manière automatique par SAS. Il répertorie toutes les variables contenues dans tous les data sets de toutes les bibliothèques actives. Il contient donc une ligne par variable.

Chaque ligne du dictionnaire contient plusieurs informations caractérisant cette variable dont :

  • la bibliothèque d’origine (variable LIBNAME)
  • le data set d’origine (variable MEMNAME)
  • le nom de la variable (variable NAME)
  • le type de la variable (variable TYPE).

Prendre un sous-ensemble du dictionnaire : Ici seule la variable STUDY est utile. Elle provient du data set EXCEL_IMPORT sauvegardé de manière temporaire dans la bibliothèque WORK.

Mettre en majuscule : Le type de la variable est soit « num » soit « char », toujours en minuscule. Le nom de la variable peut avoir un mélange de majuscules et minuscules selon la manière dont est saisi le nom lors de sa création. Pour éviter des surprises, le nom de la variable et le type sont mis en majuscule grâce à la fonction UPCASE. L’avantage des dictionnaires, c’est qu’ils peuvent lister plus d’une variable.

proc sql;
   create table dict_ref as
      select upcase(name) as name,
             upcase(type) as type
      from dictionary.columns
      where upcase(libname) = ‘WORK’ and
            upcase(memname) = ‘EXCEL_IMPORT’ and
            upcase(name)    = ‘STUDY’;
quit;

3.2 Ecrire le code et l’appeler

La deuxième étape consiste à créer un programme nommé TMP_STUD.SAS donc le nom et l’emplacement est défini dans l’instruction FILENAME. Pour écrire dans ce fichier, l’instruction FILE est ajoutée dans le DATA _NULL_. Pour plus de précisions sur l’instruction PUT, reportez-vous à l’article « Ecrire un texte avec l’instruction PUT« .

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref;
   file stud;
   put ‘data study_new;’;
   put @3 ‘set excel_import;’;
   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   put ‘run;’;
run;

%include stud;
filename stud;

L’écriture du programme est fonction des informations contenues dans le DICT_REF. Si plus d’une variable est sélectionnée, il faudrait préciser deux choses :

  • Les instructions DATA et SET ne sont à écrire qu’une fois. Elles sont ajoutées lors de la première boucle fait en interne autour de l’étape DATA via « if _N_=1 ».
  • L’instruction RUN apparaît une fois en fin de programme. Il faut donc l’ajouter une fois le dernier record du fichier de référence atteint. L’option END= de l’instruction SET crée une variable interne prenant la valeur 0 pour tous les records sauf le dernier où elle prend la valeur 1. La condition est donc basée sur cette variable.

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref end=eof;
   file stud;
   if _N_=1 then
      do;
         put ‘data study_new;’;
         put @3 ‘set excel_import;’;
      end;

   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   if eof then
 put ‘run;’;
run;

%include stud;
filename stud;

Le code sauvegardé dans le fichier TMP_STUD.SAS se présente donc ainsi, vu que la variable STUDY est de type caractère.

data study_new;
   set excel_import;
   study_new=STUDY ;
run;

L’instruction %INCLUDE permet l’exécution de ce code.

h1

Mon paramètre de macro est-il rempli ?

mai 18, 2008

Une macro sous SAS peut dans certains cas être comparée à un questionnaire. A chaque question (parameter) correspond plusieurs réponses possibles (parameter value). Certains réponses peuvent êtes obligatoires, d’autres facultatives. Dans le cas où la réponse est impérative mais n’est pas fournie par l’utilisateur, il faut pouvoir l’avertir : arrêter l’exécution du programme de manière propre et l’informer des éléments à fournir. Trois notions de programmation aideront à construire cette vérification (check).

1. Passer un message

Une condition en langage macro : ici, une macro est définie. Des instructions globales sont exécutées, si le paramètre de la macro est vide. Cette condition est donc définie avec une instruction du langage macro %IF … %THEN … %DO; …; %END;

Un message dans la log : l’objectif est d’informer l’utilisateur sur la nécessité d’une valeur pour le paramètre INPUT_VAL. Pour faire apparaître ce texte d’ERREUR dans la log, l’instruction du langage macro %PUT fera le travail.

Pas besoin de guillemets avec %IF ou %PUT : le paramètre d’une macro est une forme de macro variable. Pour retrouver sa valeur, son nom est donc entouré d’un symbole & et d’un point. Si cette valeur doit apparaître dans une chaîne de caractères entre guillemets, il faut impérativement utiliser des guillemets doubles. Dans le cas contraire, comme ici dans une instruction %IF ou %PUT, on se passe de guillemets pour résoudre la macro variable.

%macro test_param (input_val=,output_val=);
%if &input_val. = %then
   %do;
      %put ERREUR: Le macro paramètre INPUT_VAL= est obligatoire;
   %end;
*suite du programme;
%mend test_param;
%test_param (input_val=,output_val=);

Personnaliser son message : quand SAS rencontre une erreur, il utilise le mot ERROR dans la log. Pour distinguer ce message des votre, vous pouvez ajouter un mot-clé comme le nom de la macro. Par exemple : « ERROR – TEST_PARAM: the INPUT_VAL= macro parameter is mandatory. ».

2. Gérer les caractères spéciaux : il est fréquent d’avoir des valeurs autres que les chiffres et les lettres de l’alphabet comme valeur pour un paramètre de macro. Vous aurez souvent besoin de définir l’emplacement des données sources et celui où les outputs seront sauvegardées. Pour cela, les paramètres auront des valeurs du type c:/mon_projet/mesdonnees ou encore c:/mon_projet/mes_resultats. Il existe des macros fonctions : %BQUOTE et %NBRQUOTE pour tenir compte de la barre inclinée (slash) et d’autres caractères spéciaux.

  • %BQUOTE : les symboles suivants sont gérés avec la fonction %BQUOTE() : ‘  » ( ) + – * / < > = ¬ ^ ~ ; , blanc AND OR NOT EQ NE LE LT GE GT
  • %NBRQUOTE : si, en plus, vous avez les symboles & (et) et % (pourcentage), il faudra faire appel à la macro fonction %NBRQUOTE().

SAS online DOC :

  • %BQUOTE et %NBRQUOTE Functions
  • Using the %BQUOTE and %NBRQUOTE Functions

3. Enjamber un programme

Si la condition n’est pas remplie, on peut demander à SAS d’ignorer une partie du code grâce à la syntaxe de %GOTO. Il était également possible de demander à SAS d’arrêter son exécution en plein milieu. Certes, enjamber le code permet d’avoir une log plus propre, puisque seuls nos messages apparaissent. Mais surtout, cela permet de poursuivre l’exécution du programme. Ainsi, si un appel de macro ne fonctionne pas, rien n’empêche de continuer la soumission d’autres appels de cette macro.

Dans un premier temps, il s’agit de définir une balise. A partir de cette position, SAS pourra continuer son exécution. Ici, la balise s’appelle FIN_PGM. Elle est ajoutée juste avant la fin du la macro.

Dans un second temps, si le paramètre est vide, SAS est prié d’ignorer le code qui suit jusqu’à la balise. Pour cela, dans la condition, l’instruction %GOTO est ajoutée.

%macro test_param (input_val=,output_val=);
%if &input_val. = %then
   %do;
      %put ERREUR: Le macro paramètre INPUT_VAL= est obligatoire;
      %goto fin_pgm;
   %end;
*suite du programme;
%fin_pgm:
%mend test_param;
%test_param (input_val=,output_val=);

h1

Convertir une variable caractère en numérique et inversement

avril 21, 2008

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

Passer d’une variable numérique à une variable caractère ou inversement est fréquent en langage de programmation SAS. Les fonctions INPUT et PUT permettent de changer ainsi le type de la variable. Dans un premier temps, je vous propose deux exemples pour illustrer les deux situations. Dans un second temps, on verra deux emplois supplémentaires de la fonction PUT : ajouter des zéros avant et après le nombre, et passer d’une valeur caractère à une autre valeur caractère.

Exemples d’application : dans la vie courante, il est fréquent de créer une variable texte à partir de plusieurs autres. Dans le lot, il y a souvent une variable numérique. Celle-ci doit être convertie en texte avant la concaténation. A l’inverse, on peut vouloir extraire le chiffre d’une chaîne de caractère et le sauvegarder dans une variable numérique.

Note : Dans un data step, on est obligé de créer de donner un nom différent à la variable d’origine et à la nouvelle variable. Il est alors courant de renommer au préalable la variable d’origine pour pouvoir utiliser son nom pour la nouvelle variable. Ensuite, la variable d’origine est supprimée. Dans une procédure SQL, le même nom peut être utilisé.

1. Du caractère au numérique et inversement

La fonction INPUT est composée de deux paramètres : la variable texte ou directement la chaîne de caractère d’un côté, l’informat de l’autre.

Du caractère au numérique : ici, on indique à la machine qu’il faut lire la variable d’origine comme une variable texte pouvant atteindre une longueur de 16 caractères. Pour cela on utilise l’informat $16. On peut aussi choisir un informat $CHAR. : ici $CHAR16. (SAS Online Doc. : INPUT Function, Informats by Category)

data char_to_num;
x_char = ‘123456789.123456’;
x_num = input(x_char,$16.);
*x_num = 123456789.123456;
run;

Note : Pensez à ajouter un format sur la variable numérique si vous ne la lisez pas intégralement dans votre output.

Du numérique au caractère : dans l’exemple ci-dessous, on indique que la valeur caractère à créer aura jusqu’à 16 chiffres/point dont 6 après la virgule. C’est l’information donnée par le format numérique 16.6. Bien sûr, on peut avoir la longueur nombre à convertir peut-être plus petit sans risquer d’affecter la valeur. Une autre possibilité est d’utiliser le format BEST16. Si aucun nombre n’est précisé (BEST.) cela revient à BEST8. SAS cherche alors la meilleure réponse possible permettant d’entrer 8 chiffres/point. Les décimales pourront être tronquées s’il n’y a pas assez de place, voir les entiers.

data num_to_char;
y_num = 123456789.123456;
y_char = put(y_num,16.6);
*y_char = ‘123456789.123456’;
run;

2. Les plus de la fonction PUT

Ajouter des zéros aux extrémités du nouveau texte : le format z. permet de remplacer les espaces vides par des zéros. Dans l’exemple ci-dessous, la nouvelle variable aura une longueur de 8 caractères. Les deux derniers seront les chiffres après la virgule. Comme il n’y en a qu’un seul dans la variable d’origine, un zéro sera ajouté à la fin. Il reste deux espaces en début à remplir avec des zéros.

data num_char_zero;
z_num = 123.1;
z_char = put(z_num,z8.2);
*z_char = ‘00123.10’;
run;

Passer d’une valeur caractère à une autre : la valeur caractère d’origine peut aussi être du texte et non des chiffres. Dans cette situation, la nouvelle variable prend la valeur d’un format caractère souvent défini par le programmeur.

proc format;
value $cntry
FR = ‘France’
LU = ‘Luxembourg’
CH = ‘Suisse’;
run;

data char_to_char;
a1_char=’LU’;
a2_char=put(a1_char,$cntry.);
*a2_char=’Luxembourg’;
run;

Aller plus loin :

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

h1

Arrondir ses chiffres avant d’appliquer un format

mars 31, 2008

Gérer l’affichage des pourcentages et des décimales avec SAS : tel est la thématique de cet article. Les formats permettent de présenter les données d’une manière un peu plus élégante et parlante. On peut ainsi n’afficher que les deux derniers chiffres après la virgule, ajouter un symbole pourcentage. Mais les formats vont couper le chiffre plutôt que l’arrondir si PICTURE avec l’option ROUND n’est pas utilisé.

1. Arrondir un nombre avec la fonction ROUND : la fonction ROUND permet d’arrondir les nombres soit à la décimale près soit à l’entier (ou son multiple) près. La fonction dispose de deux paramètres : la variable d’origine et la précision de l’arrondi.

Arrondir à deux chiffres après la virgule :

x1= round (orig,0.01);

Arrondir tous les 10 :

x1= round (orig,10);

Ainsi dans le premier exemple, si ORIG=17.016, l’arrondi au centième (X1) est égal à 17.02. Dans le second cas, l’arrondi (X2) = 20.

2. Créer un PICTURE format : l’instruction PICTURE est très pratique pour afficher les formats dans un rapport.

Dans l’exemple qui suit, le nombre aura au maximum trois chiffres pour la partie entière et deux chiffres pour la partie décimale. Si la partie entière n’a qu’un chiffre, seul celui-ci apparaîtra. Remplacez le 0 des dizaines par un 9 et le chiffre zéro précédera le pourcentage s’il est inférieur à 10 %.

proc format;
picture pct
low-high=‘009.99 %’;
run;

Cette syntaxe dispose de l’option ROUND. C’est très pratique pour à la fois arrondir un chiffre, apposer un symbole % et avoir un zéro pour les chiffres après la virgule quand le chiffre n’est pas entre 1 et 9.

proc format;
picture pct_rd (round)
low-high=‘009.99 %’;
run;

3. Créer un texte avec un pourcentage arrondi à deux décimales : le code qui suit utilise 4 valeurs pour illustrer la différence entre la fonction ROUND, le FORMAT.

orig     fmt     rnd   solution1 solution2

21.200  21.20 %  21.20   21.20 %   21.20 %
6.333   6.33 %   6.33    6.33 %    6.33 %
84.367  84.36 % 84.37   84.37 %   84.37 %
13.362  13.36 %  13.36   13.36 %   13.36 %

data rnd_fmt;
set rnd_fmt;
fmt       = put(orig,pct.);
rnd       = round(orig,0.01);
solution1 = put(round(orig,0.01),pct.);
solution2 = put(orig,pct_rd.);
run;

Annexe :

data rnd_fmt;
input orig;
datalines;
21.200
6.333
84.367
13.362
;
run;

h1

Ecrire un texte avec l’instruction PUT

février 24, 2008

pen_fr.jpg 

Faire apparaître un message d’erreur dans la log ; afficher la valeur de variables dans la log lors du développement d’un programme ; générer plusieurs programmes similaires : voici autant d’applications de l’instruction PUT, propre au data step, qui affiche, par défaut, le texte dans la log.

1. Taper du texte brut : en mettant votre texte entre guillemets dans l’instruction PUT, celui-ci apparaîtra dans la log.

Couper l’instruction PUT : lorsqu’une instruction PUT devient longue, on doit se déplacer sur plusieurs écrans pour voir l’intégralité du programme. En coupant le texte, la lisibilité du programme et le confort du programmeur se trouvent améliorés et le texte reste continue dans la sortie LOG ou autre.

Ecrire des guillemets : pour afficher une guillemet simple, celle-ci devra apparaître dans des guillemets doubles et inversement. Pour afficher deux guillemets simples, il faudra les séparer dans deux jeux de guillemets doubles. Par défaut, on privilégiera les guillemets simples pour alléger le programme.

Ajouter un saut de ligne : à chaque nouvelle instruction PUT, SAS crée un saut de ligne. Les barres inclinées (slash /) ajoutent autant de sauts de ligne supplémentaires que désirés.

Ajouter des espaces : en écrivant une procédure SQL, on fait utile des indentations améliorant la lisibilité du code. Soit ces espaces de début de ligne sont ajoutés manuellement entre les guillemets, soit un arobas suivi du nombre d’espaces précède les guillemets (@6 crée une indentation de six espaces). 

Enlever l’espace créé par défaut avant un début de guillemets : plusieurs jeux de guillemets sont fréquemment utilisés pour insérer entre les deux le nom d’une variable. Au final, il est parfois important que la valeur de la variable et le texte qui suit se suivent sans espace. Pour cela, il faut faire reculer le curseur d’un espace en ajoutant  +(-1) avant le début de la guillemet.

2. Afficher les valeurs des variables d’un jeu de données

Afficher la valeur de la variable : pour voir la valeur des variables, il faut lister leur nom dans l’instruction PUT sans guillemet. C’est très pratique pour générer un code variant uniquement par la valeur de variables.

Afficher la valeur d’une variable et son nom : lorsqu’il s’agira de débugger un programme, vous repérerez plus rapidement dans la log vos valeurs si le nom de la variable apparaît également. Pour ce faire, vous avez deux options plus ou moins rapide.

  • Utiliser les guillemets vous obligera à écrire le nom de la variable deux fois : une fois entre guillemets et une fois sans guillemet.
  • Plus simplement, le nom de la variable est suivi du signe égal.

Lectures complémentaires : l’instruction PUT trouve tout son potentiel en combinaison avec d’autres instructions : 

  • Pas de jeu de données (DATA _NULL) : l’instruction PUT est propre au data step. Quand vous ne voudrez pas créer un jeu de données SAS dans ce data step, vous aurez besoin du DATA _NULL_.
  • Changer de destination (FILE/FILENAME) : Pour diriger votre texte vers une autre sortie que la log, vous aurez besoin de l’instruction FILE. Selon que cette sortie sera vers un fichier externe ou vers la fenêtre OUTPUT de SAS, vous aurez besoin de l’instruction globale FILENAME ou non.
  • Alterner selon les valeurs des variables (BY/FIRST/LAST) : pour générer des codes variant selon la valeur de variables, il y a l’instruction BY en combinaison avec FIRST et LAST.
  • Début et fin de texte (_N_/END=) : pour afficher un texte unique en début et en fin, on peut faire référence à la variable automatique _N_ (if _N_=1) et à une variable définie avec l’option END= de l’instruction SET.
h1

Envoyez un email via SAS

février 11, 2008

Envoyer un email via SAS

Lorsque vous écrivez un programme devant être exécuté de manière régulière, disons une routine pour faire un transfert de base de données, vous pouvez communiquer par email à votre collègue, en charge de la base, toute incohérence détectée. Je vous invite à essayer l’exemple détaillé plus loin, qui fait appel au jeu de données CLASS, disponible dans la bibliothèque SASHELP de SAS. Avec lui, un email est envoyé si un élève répertorié a 15 ans. Mais auparavant, je vous propose de comprendre le mécanisme pour envoyer un email.

1. Ecrire son message : vous écrivez via un DATA _NULL_ et des instructions (statement) PUT votre message.

2. Préciser la destination du message : puis vous indiquez vers quelle la destination votre message doit être envoyé, via le FILE statement. Si aucune incohérence n‘est détectée, vous ferez une sortie classique vers le listing (file print;). Sinon vous l’adresserez vers une référence extérieure, qu’on appellera dans notre exemple MEMO (file memo;), définie dans le FILENAME statement.

3. Créer un data set de référence : pour savoir si une incohérence existe, vous vous référerez à un data set, qui contiendra la liste des incohérences, via l’instruction SET. Lorsqu’il est vide, aucun message ne sera envoyé.

4. Alternez entre vos deux sorties via une macro variable : par défaut, il n’y aura pas d’email envoyé (file print;). Pour alterner entre les deux sorties possibles du message, on utilisera une macro variable définie dans un premier temps égal à PRINT (%let email_out=print;). Puis on changera cette valeur si besoin dans une procédure SQL avec INTO :.

5. Définir l’entête de votre email via deux mots-clés : le FILENAME statement contiendra un nom de référence. J’ai choisi MEMO ici. Puis l’email du destinataire après le mot-clé EMAIL sera listé entre guillemets. Et enfin, on ajoutera l’objet du mail via SUBJECT=’ ‘.

%let email_out=print ; 

proc sql noprint;
   create table incoherences as
      select *, 'memo' as outp
      from sashelp.class
      where age=15
      order by name;
   select distinct outp into :ema_out
      from incoherence;
quit; 

filename memo email 'veronique.bourcier@sasreference.fr'
              subject = 'Exemple de programme '; 

data _null_ ;
   set incoherences ;
   file &email_out. ;
   if _N_=1 then
      do;
         put 'Dear Administrator ';
         put // 'The SASHELP.CLASS table has ages equal to 15.';
         put // 'Records are listed below. ';
         put // 'Kind Regards, ';
         put /;
      end;
  put / NAME=;
run;
h1

Un besoin ponctuel de variables macros

janvier 24, 2008

Horloge

Cet article requiert une connaissance préalable de la syntaxe pour créer des macros et des variables macros.

1. Deux types de variables macros utilisateur : lorsque vous définissez un paramètre dans votre macro, vous créez une variable macro. Vous pouvez récupérer la valeur de cette variable macro n’importe où à l’intérieur de votre macro. Vous ne pourrez pas l’appeler en dehors de votre macro par défaut. C’est d’ailleurs ce que vous voulez la plupart du temps. Ainsi vous pourrez redéfinir une variable macro du même nom, plus tard, sans risquer d’utiliser une valeur antérieure. On parle de variable macro locale (local macro variable). Par contre, si vous voulez l’utiliser en dehors de la macro, vous devez clairement le préciser avant de lui assigner une valeur. On parle alors de variable macro globale (global macro variable).

2. Trois mots-clés pour afficher les statuts des variables macros dans la log : %put pour savoir quel statut porte votre variable macro, vous pouvez utiliser le statement propre au langage macro afin de les afficher dans la log. On fera suivre %put des mots-clés suivants :

  • _global_ ou _local_ pour limiter la sélection à un statut donné parmi les macros variables utilisateur,
  • _user_ pour voir toutes macro-variables de l’utilisateur
  • _all_ pour lister toutes les variables macros, y compris celles définies par le système SAS.

3. Changer de statut : pour qu’une variable macro a priori locale soit globale, faites usage du statement propre au langage macro %global suivi du nom des variables séparées par des espaces.

4. Un exemple de variable macro locale : Dans ce premier exemple, la variable macro est créée dans une macro. On appelle la macro et affiche la valeur de la macro variable dans la log via le %put statement inclus dans la macro. Une fois l’appel de macro terminé, on affiche toutes les variables macros pour constater que la macro variable locale n’existe plus.

%macro ex_local(x=);
   %put _all_;
%mend ex_local;
%ex_local;
%put _all_;

5. Un exemple de variable macro globale : dans ce second exemple, la macro variable définie dans la macro est préalablement enregistrée comme globale. On appelle la macro et montre sa valeur grâce au %put statement inséré dans la macro. Après l’appel de macro, on liste toutes les variables macros dans la log pour remarquer que la variable macro qui est globale est toujours présente.

%global y;
%macro ex_global(y=);
   %put _local_;
%mend ex_global;
%ex_global;
%put _all_;