Posts Tagged ‘END=’

h1

Combien de contrats ai-je au total ? (2/5) RETAIN

novembre 3, 2008

Après un premier article faisant appel à la procédure SQL pour identifier le nombre total de contrats d’un type donné à partir d’un data set SAS, voici comment un compteur dans une étape data peut résoudre le problème.

1. Renommer des variables

  • Avoir les mêmes noms en entrée et en sortie : Dans le cas présent, il faut définir de nouvelles variables ayant un nom différent de ceux existant. Pour avoir quand même au final le même nom qu’au départ, j’ai choisi de renommer mes variables d’origines rendant leur ancien nom de nouveau disponible.
  • Quel nom pour les variables ? Ces variables portent un nom commençant par un tiret bas (underscore). Cela permet d’avoir un nom toujours parlant et de les supprimer rapidement avec _: (supprimer toutes les variables commençant par un tiret bas).
data solution2 (drop=_: );
   set contrats (rename=(tel=_tel
                         habitat=_habitat);
   *...;
run;

D’autres variables sont supprimées :

  • La variable CLIENT disparaît dès de départ car il ne sert pas dans notre cas.
  • La variable NB_CNTR disparaît seulement à la fin car elle va servir pour faire nos calculs.
data solution2 (drop=_: nb_contr);
   set contrats (drop=client
                 rename=(tel=_tel
                         habitat=_habitat);
   *...;
run;

2. Créer un compteur

Une fois les variables d’origine renommées, les variables TEL et HABITAT sont initialisées à 0 avec un RETAIN. Cela veut dire que pour toutes les observations, ces variables ont dans un premier temps la valeur 0. SAS lit les observations les une après les autres. A chaque fois qu’une valeur de TEL est changée toutes celles qui suivent le sont aussi. C’est le principe du RETAIN.

data solution2 ;*(...);
   set contrats ;*(...);
   retain tel 0
          habitat 0;
   tel     = tel     + nb_cntr * _tel;
   habitat = habitat+  nb_cntr * _habitat;
run;

SAS initialise les variable TEL et HABITAT : Tout d’abord TEL=0 et HABITAT=0.

nb_cntrt _tel _habitat tel habitat
    5      1      0     0     0
    1      1      0     0     0
    2      0      1     0     0
    1      1      0     0     0
    3      0      1     0     0
    2      1      0     0     0

SAS lit la première ligne du data set : A la lecture de la première ligne du data set CONTRATS, la variable TEL est mise à jour. Sachant que pour la première observation, il a 5 contrats (NB_CNTRT=5 et _TEL=1), la première valeur de TEL est égale à 5 et toutes celles qui suivent aussi.

nb_cntrt _tel _habitat tel habitat
    5      1      0     5     0
    1      1      0     5     0
    2      0      1     5     0
    1      1      0     5     0
    3      0      1     5     0
    2      1      0     5     0

SAS lit la seconde ligne du data set : A la lecture de la seconde observation, on ajoute 1*1 à 5. Le résultat (la valeur 6) se répercute sur toutes les observations de la variable TEL.

nb_cntrt _tel _habitat tel habitat
    5      1      0     5     0
    1      1      0     6     0
    2      0      1     6     0
    1      1      0     6     0
    3      0      1     6     0
    2      1      0     6     0

SAS lit la troisième ligne du data set : A la lecture de la troisième observation, la valeur de TEL ne change pas car on ajoute zéro (0+2*0). Par contre, celle d’HABITAT change.

nb_cntrt _tel _habitat tel habitat
    5      1      0     5     0
    1      1      0     6     0
    2      0      1     6     2
    1      1      0     6     2
    3      0      1     6     2
    2      1      0     6     2

A la fin : Au final, le data set a cette forme. Ce qui nous intéresse ici ce sont les valeurs 9 et 5 de la dernière ligne d’observations.

nb_cntrt _tel _habitat tel habitat
    5      1      0     5     0
    1      1      0     6     0
    2      0      1     6     2
    1      1      0     7     2
    3      0      1     7     5
    2      1      0     9     5

3. Garder la dernière observation

A présent, il s’agit de ne garder que la dernière observation. On commence par créer une variable EOF par l’intermédiaire de l’option END= dans l’instruction SET. Le nom de la variable ici fait référence à l’expression End of File. Mais vous êtes libre de choisir le nom qui vous convient.

  • Une option sans parenthèses : On notera que END= est une option de l’instruction SET et non une option du data set CONTRATS. C’est la raison pour laquelle elle n’apparaît pas entre parenthèses.
  • Une option en fin d’instruction : Les options du data set listées entre parenthèses doivent suivre immédiatement le nom du data set. L’option END= ne peut être ajoutée qu’après.

Cette variable (EOT) a deux particularités :

  • Une variable temporaire : D’une part, elle ne sera pas conservée dans le data set final SOLUTION2 ;
  • Une variable binaire : D’autre part, la variable est binaire ; elle prend la valeur 1 pour la dernière observation, 0 autrement.
data solution2 (...);
   set contrats (...) end=eof;
   *retain ...;
   *tel=...;
   *habitat=...;
   if eof then output;
   *if eof=1 then output;
run;

La condition : Dans la condition qui suit, seule la dernière observation d’EOT a la valeur 1. C’est donc la seule qui est retenue dans la condition. Le « =1 » est implicite dans la condition. C’est pour cela que les deux instructions, celle active et celle en commentaire, sont identiques.

L’action basée sur la condition : Le mot OUTPUT redirige la ligne sélection avec la condition dans le data set final SOLUTION2.

A dans huit jours, pour retrouver une solution avec PROC MEANS.

Annexe : Rappel sur les données et l’étape data dans son ensemble :

data contrats;
   input client $ nb_cntr tel habitat;
   datalines;
a 5 1 0
b 1 1 0
c 2 0 1
d 1 1 0
e 3 0 1
f 2 1 0
;
run;

data solution2 (drop=_: nb_cntr);
   set contrats (drop=client
                 rename=(tel=_tel
                         habitat=_habitat)
                 end=eof;
   retain tel 0
          habitat 0;
   tel     = tel     + nb_cntr * _tel;
   habitat = habitat + nb_cntr * _habitat;
   if eof then output;
run;
h1

Passer d’un fichier de l’ODS TAGSET.EXCELXP à un data set SAS avec PROC IMPORT

août 15, 2008

Le programmeur SAS pourra recueillir des informations d’un non spécialiste en créer un fichier Excel. Il importe ensuite les données sous SAS.

Dans un précédent sujet « Mes 1ers pas avec ODS TAGSET.EXCELXP« , nous avons vu comment créer un fichier Excel, ou plutôt un fichier XML lisible sous Excel, à partir de la syntaxe d’ODS TAGSET.EXCELXP.

Maintenant, il s’agit de voir les limites de l’importation d’un fichier XML avec la procédure PROC IMPORT.

Exemple : Nous aurons un fichier LST_STUDY.XLS avec plusieurs feuillets, dont un nommé ‘2000’, comme exemple. Ce feuillet a deux colonnes : le numéro de l’étude (STUDY) et la variable à compléter manuellement (FLAG_EXTERNAL). La première ligne contient le nom de la colonne. La variable STUDY peut contenir des nombres et du texte.

1. PROC IMPORT a besoin de données Excel

Même si le fichier créé par ODS TAGSET.EXCELXP a une extension .xls, ce fichier est en fait un fichier en langage XML. Comment observer cette information ? Voici deux propositions :

  1. Ouvrez un fichier de ce type sous Excel et regarder le type lors que la fenêtre OUVRIR apparaît.
  2. Ouvrez le fichier dans un éditeur de texte

Afin d’utiliser la procédure PROC IMPORT, il faudra donc convertir le fichier en « enregistrant sous » et là choisir le standard Excel.

2. Les options de l’instruction PROC IMPORT

Préciser le nom du fichier d’entrée et celui de sortie : Dans l’instruction PROC IMPORT, le nom du fichier Excel est donné avec l’option DATAFILE=; celui du data set SAS est introduit par l’option OUT=. Pour rendre ce data set permanent, le nom de la bibliothèque précédera le nom du data set comme d’habitude.

Indiquer à SAS le type de fichier à lire : Selon l’environnement et la version Excel utilisée, l’option DBMS= variera. DBMS=XLS est l’option que j’utilise sous Unix et Windows pour Excel2003. Reportez-vous à la documentation en ligne PROC IMPORT Statement) pour connaître toutes les valeurs possibles de cette option.

Remplacer un fichier SAS existant : Si le data set SAS existe déjà, il ne sera pas remplacé, à moins d’ajouter l’option REPLACE.

%let resultats = C:/sasref;

proc import datafile = « &resultats./lst_study.xls »
            out      = lst_study
            dbms     = xls
            replace;
run;

3. Les Instructions sur les données sources

Après avoir vu les options de l’instruction PROC IMPORT, je vous propose trois instructions supplémentaires de la procédure (SAS Online Doc. : Data Source Statements)

Des noms de variables personnalisés avec GETNAMES=YES : SAS se sert de la première ligne du fichier Excel pour définir le nom des variables SAS à moins que l’instruction GETNAMES=NO soit ajoutée.

SAS considère les premières lignes du fichier pour identifier le type des variables sauf si MIXED=YES : Si on a une combinaison de caractères et chiffres, on peut se retrouver avec des valeurs manquantes. Par exemple, si vous avez une variable année contenant les valeurs 2008, 2007, <2007, il faudra importer les variables sous forme de caractère. L’instruction MIXED=YES fera le travail pour vous. 

Importer une feuille de calcul en particulier grâce à SHEET=: Par défaut, SAS importera la première feuille de calcul disponible dans le fichier Excel. Pour choisir un autre feuillet, son nom est donné entre guillemets dans l’instruction  SHEET=.

%let resultats = C:/sasref;

proc import datafile = « &resultats./lst_study.xls »
            out      = lst_study
            dbms     = xls
            replace;
   *getnames = yes;
   mixed    = yes;
   sheet    = ‘2000’;
run;

Vous trouverez plus d’informations sur la procédure PROC IMPORT dans l’aide en ligne : SAS Online Doc, The IMPORT Procedure.

4. Une spécificité de l’ODS TAGSET.EXCELXP à gérer

Lors de la création du fichier avec ODS TAGSET.EXCELXP, une ligne est parfois ajoutée après la dernière ligne de saisie. Cette ligne est incluse dans le data set SAS à l’importation. La raison pour laquelle cette ligne est saisie m’est inconnue.

Par contre, je vous propose un data step pour vous en débarrasser une fois le data set SAS créé. 

  • L’option END= de l’instruction SET sert à repérer la dernière ligne d’observations.
  • La fonction MISSING permet de ne supprimer la ligne que si notre variable STUDY est vide.

data lst_study;
   set lst_study end=eof;
   if eof and missing(study) then delete;
run;

h1

9 points autour de la notion d’octet

juillet 28, 2008

L’octet (byte en anglais) est une unité de mesure informatique utilisée en SAS pour définir la longueur des variables. Il permet de stocker 1 caractère parmi une liste de 256. Une des listes de caractères les plus répandue est la table des ASCII (American Standard Code for Information Interchange). SAS dispose de deux fonctions RANK et BYTE pour passer d’un nombre à un de ces caractères et inversement. Ces notions sont à découvrir ou redécouvrir sous la forme de 9 points.

1. Des notions mathématiques mises à la sauce informatique

Deux valeurs possibles avec les booléens : Les booléens (boolean) sont des valeurs égales à 0 ou à 1. C’est une notation mathématique. On parle souvent de la logique des booléens. L’interprétation de ces valeurs est :

  • 0 pour faux (false)
  • 1 pour vrai (true)

En SAS, les syntaxes FIRST/LAST et END= du data step se servent de la logique des booléens.

Le bit est l’unité informatique de base : L’unité de mesure élémentaire en informatique, le bit (bit en anglais également) est basé sur le même principe. Le bit prend soit la valeur 0, soit la valeur 1.

L’octet est un groupement de 8 bits : Un octet (byte en anglais) est égal à la combinaison de 8 unités élémentaires, de 8 bits.

2. Le but du jeu

En informatique, le but du jeu est de n’utiliser que des valeurs 0/1 pour faire référence à des nombres entiers. Pour avoir un éventail de nombre entier assez large, il faut donc plusieurs bits.

Ensuite, pour chaque nombre entier une valeur peut être assignée. Par exemples, les nombres allant de 0 à 255 servent dans une table de référence pour les caractères, la table des ASCII.

3. Combien de valeurs différentes sont extraites avec x bits ? 

Tout d’abord, les bits sont mis les uns à la suite des autres.

  • Avec 1 bit : le bit prend soit la valeur 0 soit la valeur 1.
  • Avec 2 bits : les valeurs de 2 bits s’arrangent de 4 manières différentes à savoir 00, 01, 10 ou 11.
  • Avec 3 bits : les valeurs de 3 bits peuvent se présenter de 8 manières possibles 000, 001, 010, 011, 100, 101, 110, 111.

Généralisation : Pour savoir combien d’arrangements de 0 et 1 sont possibles, le nombre 2 (nombre de valeurs possibles dans un bit) est multiplié autant de fois qu’il y a de bits, soit 2x. En termes mathématiques, on parle du nombre d’arrangements avec répétition. Il s’agit bien du calcul avec répétition car les valeurs 0 et/ou 1 peuvent apparaître plusieurs fois.

Ecrire un exposant sous SAS : Pour mettre une valeur en exposant sous SAS, on fait suivre la base de 2 étoiles et de l’exposant. Voici un exemple pour une variable nommée EXPOSANT.

  • En langage mathématique : exposant=28
  • Sous SAS : exposant=2**8;

4. Quelle position pour mon bit ?

On commence par regarder celui qui est le plus à droite et on lui assigne la position 0. Celui qui suit aura une position 1, etc.

  • Avec 1 bit : le bit est en position 0.
  • Avec 2 bits : le premier bit est en position 1, le second en position 0.
  • Avec 3 bits : le premier bit est en position 2, le second en position 1 et le dernier en position 0.
  • Etc.

5. Création d’une liste de valeurs

Maintenant que la position (x) de chaque bit est connue, on va additionner des valeurs 2x à chaque fois que le bit est égal à 1. Voici donc quelques exemples avec 1, 2 et 3 bits. D’un côté, on a l’arrangement des bites, de l’autre la valeur que l’on peut en extraire.

Avec 1 bit, les valeurs finales sont entre 0 et 1.

  • « 0 » : 0
  • « 1 » : 20 = 1

Avec 2 bits, les valeurs finales sont entre 0 et 3.

  • « 00 » : 0 + 0 = 0
  • « 01 » : 0 + 20 = 0 + 1 = 1
  • « 10 » : 21 + 0 = 2 + 0 = 2
  • « 11″ : 21 + 20 = 2 + 1 = 3

Avec 3 bits, les valeurs finales sont entre 0 et 7.

  • « 000 » : 0 + 0 + 0 = 0
  • « 001 » : 0 + 0 + 20 = 0 + 0  + 1 = 1
  • « 010 » : 0 + 21+ 0 = 0 + 2 + 0 = 2
  • « 011 » : 0 + 21+ 20 = 0 + 1+ 2 = 3
  • « 100 » : 22 + 0 + 0 = 4 + 0 + 0 = 4
  • « 101 » : 22 + 0 + 20 = 4 + 0 + 1 =5
  • « 110 » : 22 + 21 + 0 = 4 + 2 + 0 = 6
  • « 111″ : 22 + 21+ 20 = 4 + 2 + 1 = 7

Avec 8 bits (1 octet) les valeurs vont de 0 à 255. Comme indiqué précédemment ces nombres servent pour la table des ASCII.

6. La table des ASCII et les fonctions RANK/BYTE

La table des ASCII regroupe les caractères en trois groupes :

  • 0-31 : les codes de contrôle (control code) comme « passage à la ligne »
  • 32-127 : les caractères imprimables (printable characters)
  • 128-255 : les caractères spéciaux (special characters) comme é, à, û…

Note pour les claviers étrangers : La liste des caractères spéciaux est pratique à l’étranger lorsqu’un clavier d’ordinateur ne dispose pas des accents. Ainsi pour obtenir la lettre « é », maintenez la touche « Alt » enfoncé et tapez le nombre 0233. Voici ceux que j’utilise le plus souvent :

  • 0224 à
  • 0226 â
  • 0231 ç
  • 0233 é
  • 0234 ê
  • 0235 è
  • 0238 î
  • 0244 ô
  • 0249 ù
  • 0251 û

Exemples d’applications : Dans le cadre des fonctions SAS, je vais me concentrer sur les valeurs 32 à 255 car ce sont les valeurs que j’ai rencontré dans des data sets SAS. J’ai aussi eu besoin de vérifier qu’une macro pouvait toujours fonctionner quand elle rencontrait ces caractères dans un data set. Pour se faire, j’ai eu besoin de créer un data set les contenant.

7. Convertir un nombre en caractère (la fonction BYTE)

Dans cet exemple, la fonction BYTE génère toutes les valeurs ASCII imprimables et les sauvegarde dans une variable ASCII. Pour ce faire, une boucle est construite avec les instructions DO et END. C’est l’occasion d’introduire rapidement sous forme d’exemple la notion de boucle.

data one (drop=i);
   do i=32 to 127;
   *do i=128 to 255;
      ascii=byte(i);
      output;
   end;
run;

La boucle est définie par variable i allant de 32 à 128 (et non 127) mais l’action est conduite seulement pour les valeurs 32 à 127. Les valeurs intermédiaires sont distantes d’une valeur 1 car l’incrémentation par défaut est 1. Pour changer cette valeur par défaut et disons prendre une valeur sur deux, on ajoute BY 2 dans l’instruction DO.

A chaque fin de boucle i est incrémenté par 1. Quand i=127, la valeur est calculée une dernière fois. Puis i est incrémenté  par 1. Avec i=128, la condition n’est plus remplie. Le contenu de la boucle est ignoré. SAS s’intéresse à l’étape suivante dans le data step. Ici l’étape suivante est la suppression de la variable i définissant la boucle.

A chaque nouvelle valeur de la variable i, la variable ASCII est recalculée. Puis le record est ajouté dans le data set ONE grâce à l’instruction OUTPUT.

8. Convertir un caractère ASCII en nombre (la fonction RANK)

Dans cet exemple, la fonction RANK retourne la valeur numérique de la table ASCII pour la lettre « é ». Cette valeur est sauvegardée dans la variable VAL_NUM.

data two;
   val_num=rank(‘é’);
run

9. Les multiples des octets dans le commerce

Dans le monde des disques durs…, et taille de fichiers…., vous entendez couramment parler de :

  • Kilooctet ou Ko (Kilo Byte KB en anglais),
  • Megaoctet ou Mo (Mega Byte MB),
  • Gigaoctet ou Go (Giga Byte GB),
  • Teraoctet ou To (Tera Byte TB).

A l’avenir, on entendre peut-être même parle de :

  • Petaoctet ou Po (Peta Byte PB),
  • Exaoctet ou Eo (Exa Byte EB),
  • Zebioctet ou Zo (Zebi Byte ZB),
  • Yobioctet ou Yo (Yobi Byte YB).

La Commission Electrotechnique International (International Electrotechnique Commission IEC) a développé un standard se basant sur des multiples de 10 de l’octet. Cependant, l’ancien standard peut encore être rencontré.

  • Nouveau standard : un Kilooctet est 1 000 octets (103). Un Megaoctet est 1 000 000 (106).
  • Ancien standard : un Kilooctet représente 1 024 octets (210). Pour le Megaoctet, on passe à 1 048 576 (220).

En résumé, en achetant un disque dur de 500 Go, le produit est plus intéressant s’il réfère à l’ancien standard car il aura une plus grande capacité. Par contre, si on a un fichier de 5 Mo à envoyer, il représente moins de volume si on parle avec le nouveau standard.

h1

Penser conditionnel (3/3) : CASE WHEN

juillet 3, 2008

Après avoir présenté les deux alternatives sous SAS dans un data step pour définir des conditions (La base du IF et SELECT), partons voir la syntaxe de PROC SQL pour définir une nouvelle variable.

1. Différences et ressemblances avec les IF et SELECT

Différences : A la différence des deux syntaxes du data step,…

  • … une seule action est possible pour une condition donnée : à savoir définir une et une seule nouvelle variable ou macro variable. Les conditions ne peuvent dont pas servir pour créer de nouveaux data sets ou imbriquer des conditions dans d’autres conditions.
  • … le nom de la nouvelle variable n’est donné qu’une seule fois.

Ressemblances :

  • Comme dans SELECT WHEN et ELSE IF,  seuls les records non déjà valides pour les cas listés précédemment sont relus.
  • Comme IF THEN, une dernière condition ELSE liste tous les cas non sélectionnés auparavant.

Un des avantages de la procédure SQL est de pouvoir définir une nouvelle variable à partir d’une ancienne variable portant le même nom. Alors que dans un data step, cela se passe en plusieurs étapes : 

  • Tout d’abord, la variable est renommée pour pouvoir se servir de son nom d’origine pour la nouvelle variable.
  • Ensuite la variable d’origine portant le nom créé uniquement pour l’occasion est supprimée.

Un autre avantage est l’usage des fonctions et du mot-clé DISTINCT.

2. La syntaxe CASE WHEN en exemple

2.1 Définir une variable à partir de plusieurs variables

Dans cet exemple, la variable POP prend au maximum 4 valeurs :

  • 1 si la variable AGE est supérieure à 13 et la variable SEX est égale à F ;
  • 2 si l’AGE est entre 0 et 13 et qu’il s’agit d’une femme ;
  • 3 si il s’agit d’un homme et que l’âge est une valeur positive ;
  • valeur manquante enfin pour les autres cas.

proc sql;
   /*create table class as*/
   select *, case
               when age > 13 and sex=‘F’ then 1
               when age >= 0 and sex=‘F’ then 2
               when age < 0 or sex not in (‘F’,‘M’) then .
               else 3
           end as pop
   from sashelp.class;
quit;

2.2 Utiliser les fonctions

Dans l’exemple ci-dessous, le critère est appliqué par groupe de valeurs définies dans la variable SEX. En regardant les données, deux groupes de valeurs apparaissent : ‘F’ pour les femmes et ‘M’ pour les hommes. La variable MAX_AGE1 est égale à ’13’ si, pour un groupe donné, la valeur maximale observée parmi les valeurs non manquantes de la variable AGE est 13. Sinon, MAX_AGE1 prend la valeur ‘N/A’.

proc sql;
   select sex, case
                 when max(age) = 13 then ’13’
                 else ‘N/A’
               end as max_age1
   from sashelp.class
   group by sex;
quit;

A présent, vu qu’il n’y a qu’un critère définissant la condition et qu’une seule valeur n’est attendue, ce critère peut être donné en début.

proc sql;
   select sex, case max(age)
                 when (13) then ’13’
                 else ‘N/A’
               end as max_age2
   from sashelp.class
   group by sex;
quit;

Mais, il est bon de se demander si un format ne serait pas plus adapté dans ce cas.

proc format;
  value max_age
   13    = ’13’
   other = ‘N/A’;
run;

proc sql;
   select sex, put(max(age),max_age.) as max_age2
   from sashelp.class
   group by sex;
quit

2.3 Créer une macro variable

Voici pour terminer un petit exemple où une macro variable POP est crée. Sa valeur dépend de l’âge maximum observé dans le data set.

proc sql; *noprint;
   select case
            when
max(age) > 13 then ‘>13’
            when max(age) >= 0 then ‘[0-13]’
            else ‘N/A’
          end into :pop
   from sashelp.class;
quit;

h1

Penser conditionnel (1/3) : La base du IF

juin 19, 2008

Selon que des variables aient certaines valeurs ou non, le programmeur peut décider de créer une nouvelle variable, extraire une ligne d’observation, etc.

SAS propose plusieurs syntaxes pour exprimer ces conditions.

  • Dans le data step et la procédure SQL, pour extraire un sous ensemble de records sans autre action le WHERE est probablement le plus adapté. De plus, dans d’autres cas que le data step et la PROC SQL l’option WHERE est aussi utilisable (PROC SORT, PROC FREQ, ODS OUTPUT…).
  • Sinon, dans un data step, on rencontre le IF et le SELECT et dans une procédure SQL, CASE WHEN est disponible.

Ce sujet sera divisé en 3 articles à commencer par la syntaxe du IF. Dans huit jours, le prochain rendez-vous sera consacré au SELECT. Enfin le dernier article de la série s’intéressera au CASE WHEN.

1. Le minimum ou presque

« S’il pleut, alors je prend mon parapluie, sinon, je le laisse au bureau. » Dans cette phrase, on repère trois mots : si, alors, sinon. Traduisez par IF, THEN, ELSE. C’est trois mots, version anglaise, forme la syntaxe de base.

Dans l’exemple suivant, on considère les variables AGE et SEX pour créer la variable PP_NY (per protocol population, no/yes) : « Si ma variable âge est supérieure à 13 et qu’il s’agit d’hommes alors ma variable pp_ny=1, sinon pp_ny=0. »

data class;
set sashelp.class;
if age > 13 and sex=‘M’ then pp_ny=1;
else pp_ny=0;
run;

On remarquera l’usage de l’instruction finale ELSE pour inclure tous les cas non pris en compte précédemment.

2. Multiplier les combinaisons

Dans ce second exemple, une instruction ELSE IF a été ajoutée. Ainsi tous les hommes de 13 ans ou moins pour lesquels on connaît l’âge sont sélectionnés dans cette seconde instruction. Enfin, les valeurs restantes correspondent aux lignes d’observations où l’âge est manquant ou concernant les femmes.

data class;
set sashelp.class;
if age > 13 and sex=‘M’ then pp_ny=1;
else if age > .z and sex=‘M’ then pp_ny=0;
else pp_ny=.;
run;

 

ELSE IF : il est préférable d’utiliser le ELSE IF, plutôt que le IF pour des raisons de performance et pour éviter des erreurs d’étourderie.

  • Par performance j’entends : seules les observations qui ne sont pas valides dans la première condition sont lues pour évaluer la condition suivante. C’est un temps très précieux quand on traite une grosse base de données.
  • Par erreur j’entends : en aucun cas, des observations peuvent-être sélectionnées par deux instructions. Ainsi si PP_NY=1, il n’y a aucune chance qu’il devienne PP_NY=0 après exécution de la seconde instruction.

Important : dans l’exemple précédent, j’ai volontairement choisi de lister plus d’une variable pour définir ma condition. En effet, si vous avez une seule variable en entrée et une seule variable en sortie, un informat suffit. Plusieurs avantages se cachent derrière :

  • le programme est allégé
  • l’accès aux valeurs est plus évident puisque les formats font partie des informations données en début de programme.

Voici ce que cela donnerait si on ne considérerait que la variable AGE pour définir la variable PP_NY.

proc format;
   invalue age_pp
   ._.z    = .
low-13   = 0
   13
<-high = 1;
run;

data class;
   set sashelp.class;
pp_ny=input(age,age_pp.);
run;

3. Parenthèse sur les valeurs manquantes 

On a fait très attention de ne pas inclure les âges manquants pour définir PP_NY=1/0. La valeur .z est une valeur manquante spéciale « special missing ». SAS en compte 27.

L’intérêt des valeurs manquantes spéciales : le but des special missings est d’offrir d’un éventail de valeurs pour distinguer les valeurs manquantes. Prenez le cas d’une variable indiquant le contraceptif médicamenteux pris par le patient. S’il s’agit d’une femme et que l’information n’est pas fournie, on mettra manquant (un point). Par contre, s’il s’agit d’un homme, on marquera .A pour « non applicable ». Un format permettra ensuite de représenter . par MISSING et .A par N/A.

L’ordre des valeurs manquantes : l’ordre des missings et special missings est important à connaître. Cela vous expliquera pourquoi j’ai utiliser .z et non . dans l’exemple précédent. Vous pouvez vous reporter à la Online Doc : Missing Values. En résumé cela donne :

  • ._ pour le plus petit,
  • . juste après,
  • .A
  • .Z pour le plus grand des special missings
  • valeurs négatives
  • valeurs positives

Alternative avec la fonction MISSING : sachez qu’une autre solution pour exclure toutes les valeurs manquantes (missing et special missing), c’est d’utiliser la fonction MISSING qui a pour autre avantage de s’appliquer autant aux valeurs textes qu’aux valeurs numériques. C’est très pratique quand on ne connaît pas à l’avance le type de la variable. Dans la PROC SQL, WHERE… il y a aussi « WHERE x IS MISSING ».

4. Plusieurs actions quand une condition est remplie (DO-END)

Si une condition est remplie, il peut s’avérer nécessaire de faire plusieurs choses. Par exemple, on peut à la fois créer une nouvelle variable et sortir la ligne d’observations.

Dans l’exemple ci-dessous, la variable SEX ne prend que les valeurs ‘M’ et ‘F’. Dans ce cas précis, au final, il y a plus de records à la fin. Tout d’abord, tous les records sont extraits et POP est défini comme étant égal à 1. Ensuite, pour les records masculins, les records sont sortis une deuxième fois et notre variable POP est alors égale à 2.

data class;
set sashelp.class;
pop=1;
output;
if sex=‘M’ then
do;
pop=2;
output;
end;
run;

h1

Insérer quelques nouvelles observations

juin 9, 2008

Dans l’article ‘Ajouter des lignes en combinant des data sets’, nous avons vu comment ajouter des observations en joignant plusieurs data sets. Ici, il s’agit de voir comment ajouter manuellement un nombre limité d’observations en fin de data set. Deux méthodes sont proposées : un data step avec l’option END= et l’instruction OUTPUT d’une part et l’instruction INSERT INTO de PROC SQL d’autre part.

1. Passer par un data step pour ajouter une ou plusieurs observations

L’instruction SET dispose de l’option END=. Celle-ci permet de définir une nouvelle variable. On peut s’imaginer cette variable comme une variable binaire prenant une valeur zéro pour toutes les observations sauf la dernière. Il est courant de nommer cette variable EOF, acronyme pour END OF FILE (fin de fichier).

Dans un premier temps, toutes les observations sont lues et envoyées dans le data set de sortie avec OUTPUT.

Dans un second temps, on précise à SAS que si notre variable binaire a une valeur de 1, l’observation va être de nouveau envoyée dans le data set final après avoir changé les valeurs de son choix.

Lorsque la valeur prise par la variable binaire n’est pas précisée (if eof then…), SAS assume ‘if eof=1 then…’ ou en d’autres termes ‘si la condition est vraie alors…’. Pour information, l’inverse est ‘if not eof then…’ ou ‘if eof=0 then…’.

data class;
   set sashelp.class end=eof;
   output;
   if eof then
      do;
         name=‘SASREF’;
         sex=‘F’;
         age=18;
         height=.;
         weight=100;
         output;
         name=‘SASREF’;
         sex=‘M’;
         age=.;
         height=.;
         weight=.;
         output;
      end;
run;

Cette méthode reste très contraignante. Car il faut redéfinir tous les champs au risque sinon d’avoir une valeur de l’ancienne observation. La procédure SQL est véritablement conçue pour répondre à notre besoin.

2. L’instruction INSERT de la procédure PROC SQL

Deux syntaxes sont disponibles avec l’instruction INSERT selon qu’on liste seulement les valeurs, mais pour toutes les variables ou qu’on liste à la fois les variables et leur valeurs mais seulement celles qui nous intéresse.

Ma préférence va à la seconde solution, car elle évite des erreurs dans l’ordre d’affichage des valeurs. De plus, lorsqu’on relit un programme, il est facile de faire le lien entre une valeur et la variable à laquelle elle réfère.

 2.1 Lister toutes les valeurs pour une ligne d’observation sans le nom des variables : chaque nouvelle ligne d’observation est introduite par le mot-clé VALUES. Il n’y a donc pas besoin de délimiteur entre chaque ligne d’observation. Toutes les valeurs pour une observation donnée sont listées entre parenthèses et séparées par une virgule.

proc sql;
   insert into class
   values (‘SASREF2’,‘F’,18,.,100)
   values (‘REFSAS2’,‘M’,.,.,.);
quit;

 2.2 Lister les variables qui nous intéressent seulement : chaque nouvelle ligne d’observation est introduite par le mot-clé SET. Comme précédemment, il n’y a pas de délimiteur entre chaque ligne d’observation nouvellement définie. Les variables sont listées dans un ordre quelconque. Les variables non listées prennent une valeur manquante.

proc sql;
   insert into class
   set sex=‘F’, name=‘SASREF3’,age=18,weight=100
   set name=‘REFSAS3’, sex=‘M’;
quit;

Pour plus de précisions sur l’instruction INSERT, vous pouvez vous reporter à  la SAS Online Doc. : Insert Statement.

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

Repérer les 1ers/derniers records (FIRST/LAST)

mai 6, 2008

Repérer la première et/ou la dernière observation d’un jeu de données ou d’un sous-ensemble de ce jeu, c’est possible sous SAS avec les mots-clés FIRST et LAST dans un data step. On se sert de cette information sous forme de condition. Si la première observation est rencontrée, on fait ceci, sinon on fait cela. Cela sert pour créer une variable compteur ou pour générer plusieurs programmes via un DATA _NULL_, programmes variant par quelques valeurs listées dans un fichier de référence.

1. Le raisonnement FIRST/LAST en langage humain

Dans l’exemple ci-dessous, on a tout d’abord deux variables MEMNAME et NAME qui sont triées. Ensuite sont ajoutées plusieurs variables.

Les variables FRST_DSN/LST_DSN

  • S’il s’agit de la première fois que l’on lit la valeur de la variable MEMNAME, alors on donne une value de 1 à FRST_DSN, sinon on donne une valeur de 0.
  • Si au contraire, il s’agit de la dernière valeur avant de changer, LST_DSN prend la valeur 1, sinon il prend la valeur 0.

Dans l’exemple, on remarque que FRST_DSN et LST_DSN sont toutes les deux égale à 1 quand MEMNAME=DSN2, car il n’y a qu’une observation pour ce MEMNAME. La première observation est donc également la dernière,

memname  name  frst_dsn lst_dsn frst_var lst_var
    dsn1       var1          1          0           1          0
    dsn1       var1          0          0           0          0
    dsn1       var1          0          0           0          1
    dsn1       var2          0          0           1          1
    dsn1       var3          0          1           1          1    
    dsn2       var1          1          1           1          1    

    dsn3       var1          1          0           1          1
    dsn3       var2          0          0           1          1
    dsn3       var3          0          0           1          1
    dsn3       var4          0          1           1          1    
    dsn4       var1          1          0           1          1
    dsn4       var2          0          1           1          1       

FRST_VAR/LST_VAR : une fois dans un groupe (DSN1, DSN2, DSN3 ou DSN4), on regarde la seconde variable NAME.

  • Si on a la première fois la valeur dans ce groupe, FRST_VAR=1 sinon FRST_VAR=0.
  • Si au contraire, il s’agit de la dernière fois qu’on l’observe dans ce group, LST_VAR=1, 0 autrement.

Dans l’exemple, seul le DSN1 a plusieurs fois une VAR1 associée. C’est donc le seul moment où FRST_VAR n’est pas égal à LST_VAR.

NOTE, choix de l’auteur : entendez FRST pour rappeler le mot FIRST (premier), LST le mot LAST (dernier) et DSN le mot DATA SET NAME (nom du jeu de données).

2. Le raisonnement FIRST/LAST en langage SAS

SAS lie les données d’un jeu de données ligne par ligne. On rassemble les données par groupe en les triant. On rappelle cet ordre avec une instruction BY.

Ici les variables MEMNAME et NAME sont extraites de la bibliothèque SASHELP grâce au dictionnaire COLUMN.

proc sql;
   create table lst_dsn_var as
   select memname, name
   from dictionary.columns
   where upcase(libname)=’SASHELP’;
quit;

Puis, chacune des variables FRST_DSN, LST_DSN, FRST_VAR et LST_VAR sont crées. Ces variables prennent une valeur de 1, si la condition est vrai (s’il s’agit bien de la première ou de la dernière observation), 0 sinon. Bien sûr, on peut choisir de leur donner la valeur que l’on veut.

data _null_;
   set lst_dsn_var;
   by memname name;
   if first.memname then frst_dsn=1;
   else frst_dsn=0;
   if last.memname then lst_dsn=1;
   else lst_dsn=0;
   if first.name then frst_var=1;
   else frst_var=0;
   if last.name then lst_var=1;
   else lst_var=0;
run;

NOTE : SAS se base sur les données d’origine pour dire si oui ou non, il s’agit de la première/dernière observation. Dès lors, si le jeu d’origine est altéré (suppression de lignes), SAS ne redéfinira pas une première/dernière observation parmi celles restantes. On peut donc ne plus avoir l’observation considérée par SAS comme première/dernière. Il choisira si besoin de faire les deux opérations dans des data steps distincts.

3. La première et la dernière observation d’un data set

Vous n’aurez pas toujours une variable prenant la même valeur pour toutes les observations et ainsi retrouver la première et la dernière observation. On peut soit en créer une avec un RETAIN par exemple ou plus simplement utiliser

  • la variable automatique _N_ pour la première observation et
  • la variable assignée avec l’option END= dans l’instruction SET pour la dernière observation.

data _null_;
   set lst_dsn_var end=eof;
   if _N_=1 then …;
   if eof then…;
run;

NOTE : Par habitude, on donne ici le nom EOF (End Of File) comme nom à la variable qui prend une valeur 1 s’il s’agit de la dernière observation, 0 autrement. Comme la variable automatique _N_, EOF n’apparaît pas dans le data set final, s’il est créé.