Archive for the ‘Data Management’ Category

h1

Mettre à jour un data set à partir d’un autre

octobre 30, 2008

Si vous avez déjà utilisé un peu SAS, vous connaissez probablement les instructions SET et MERGE. Aujourd’hui, voici un article sur l’instruction UPDATE pour mettre à jour un data set. Cette instruction de l’étape DATA doit être utilisée en gardant en tête deux notions importantes expliquées ici.

Pour réviser ou découvrir les instructions SET et MERGE, reportez-vous aux articles suivants :

1. Un data set de base et un autre contenant des informations nouvelles

Dans notre exemple nous avons deux data sets YEAR_2007_FRST et YEAR_2007_EXTRA.

Le premier data set YEAR_2007_FRST est le data set à mettre à jour : il contient

  • 4 observations et
  • 3 variables numériques : MONTH (month pour mois), CRIT (criteria pour critère), VAL (value pour valeur).
data year_2007_frst;
   input month crit val;
   datalines;
1 2 3
4 5 6
9 9 9
10 10 10
;
run;

Le second data set YEAR_2007_EXTRA contient des informations à ajouter au premier data set. Il est composé de :

  • 5 observations : certaines lignes d’observations du premier data set sont présentes mais pas toutes. Il y a aussi des lignes d’observations en plus. Parfois la valeur de la variable MONTH est identique mais par forcément celle des autres variables.
  • 4 variables numériques : il y a les variables déjà présentes auparavant et une nouvelle variable.
data year_2007_extra;
   input month crit val val2;
   datalines;
1 2 3 4
1 4 5 6
7 8 9 10
9 9 . 9
10 10 .A 10
;
run;

2. Choisir une ou plusieurs variable clés

Avec l’instruction UPDATE, il faut définir une liste de variables clés. Lorsque la combinaison est présente dans les deux fichiers, les autres variables sont mises à jour. Sinon, une nouvelle ligne d’observations est ajoutée.

Ici, je choisis de désigner une ligne avec la variable MONTH et seulement la variable MONTH. Lorsque la variable MONTH du premier et du second data sets coïncident, les autres observations sont mises à jour en se servant du deuxième fichier (YEAR_2007_EXTRA).

data year_2007_frst;
   update year_2007_frst
          year_2007_extra;
   by month;
run;

Ajouter de nouvelles observations : Avec l’exemple de l’article, la ligne où MONTH = 7 n’est pas présente dans le premier data set. Elle est ajoutée.

Ajouter de nouvelles variables : La variable VAL2 est également nouvelle et ajoutée.

3. Une seule ligne d’observation par clé dans le fichier additionnel

Lorsque le fichier additionnel (WEAR_2007_EXTRA) contient plusieurs observations, seule une est gardée. Il est donc préférable d’avoir un fichier avec une seule ligne d’observation par variable clé.

Dans notre exemple, le fichier servant pour la mise à jour a deux lignes d’observations avec MONTH égales à 1. SAS utilisera, dans un premier temps, la première pour mettre à jour le fichier. Puis réécrira dessus avec la seconde ligne d’observation.

  • Avant :MONTH=1, CRIT=2, VAL=3
  • Après : MONTH=1, CRIT=4, VAL=5 et VAL2=6.

4. Ignorer les valeurs manquantes du fichier de mise à jour

Si dans votre fichier de mise à jour il y a des valeurs manquantes alors que dans le fichier d’origine ce n’était pas le cas, SAS n’effacera pas la valeur sauf si la nouvelle valeur est une valeur manquante particulière (special missing).

Dans notre exemple,

  • quand MONTH=9, VAL=9 avant et après, même si dans le data set additionnel, VAL était manquant (symbole point).
  • quand MONTH=10, VAL=10 avant et VAL=.A après, car la nouvelle valeur est une valeur qualifiée par SAS de valeur manquante spéciale.

Au final le nouveau fichier YEAR_2007_FRST, auquel un autre nom aurait pu être donné, se présente ainsi :

month crit val val2
  1     4   5    6
  4     5   6    .
  7     8   9   10
  9     9   9    9
  10   10  .A   10

5. Avoir une seule ligne par BY variable dans le fichier à mettre à jour

Après avoir noté que SAS ne remplace pas les valeurs existantes par des valeurs manquantes, je tenais à souligner une seconde particularité du UPDATE. SAS estime que la variable clé devrait identifier de manière unique une ligne d’observations dans le fichier à mettre à jour.

Dans notre exemple, SAS que la variable clé est MONTH. Il estime que chaque valeur de MONTH se doit d’être unique dans le fichier à actualiser (YEAR_2007_FRST).

Je vais donc ajouter une ligne pour que MONTH=1 apparaisse deux fois et voir la gestion qu’en fait SAS.

data year_2007_frst;
   input month crit val;
   datalines;
1 2 3
1 9 9
4 5 6
9 9 9
10 10 10
;
run;

Si ce n’est pas le cas deux choses se passe :

  • D’une part, un WARNING apparaît dans la log.
  • D’autre part, parmi les lignes ayant les mêmes valeurs clés, seule la première ligne sera actualisée.

Ici, la log contiendra le WARNING suivant :

  • WARNING: The MASTER data set contains more than one observation for a  BY group.

Et notre fichier final, lorsque la variable MONTH =1, seule aura

month crit val val2
  1     4   5    6
  1     9   9    .
  4     5   6    .
  7     8   9   10
  9     9   9    9
  10   10  .A   10

En résumé, avec une instruction UPDATE, il est important de garder à l’esprit trois notions :

  • les valeurs manquantes simples n’effacent pas les données d’origine.
  • le data set avec les données actualisées contiendra une seule ligne d’observation par variable clé et des conséquences si ce n’est pas le cas.
  • le data set à actualiser doit contenir une seule ligne d’observation par variable clé et ainsi respecter la définition de la syntaxe.

Vous trouverez dans la documentation en ligne une page sur UPDATE Statement pour compléter votre lecture.

h1

Combien de contrats ai-je au total ? (1/5) PROC SQL

octobre 27, 2008

Sur le forum www.commentcamarche.net, j’ai rencontré une question pour laquelle une série d’articles seront rédigés et ainsi pour présenter différentes solutions. Je commence aujourd’hui avec une procédure SQL précédée d’une introduction sur les données. Les quatre prochains articles utiliseront les compteurs, les procédures PROC MEANS, PROC FREQ et PROC TABULATE.

1. Les données

On part d’un fichier contenant une liste de clients et deux types de contrats : téléphone (tel) et habitation (habitat).

  • Une variable TEL indique si oui ou non le client a un contrat de téléphone peu importe qu’il s’agisse d’une ligne fixe, d’un téléphone portable personnel. Une variable NB_CNTR précise le nombre de contrats de ce type le client a signé.
  • Une variable HABITAT indique si oui ou non le client a un contrat en relation avec son habitat qu’il s’agisse de sa maison principale, sa maison secondaire ou d’un contrat de location pour ses enfants partis étudiés, etc. La variable NB_CNTR précise comme précédemment le nombre de contrats de ce type souscrit par le client.
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;

Objectif : Le but du jeu est de retrouver le nombre total de contrats téléphoniques et de contrats d’habitation, soit 9 dans le premier cas (5+1+1+2) et 5 dans le second cas (2+3).

2. La procédure SQL

Dans cet exemple, un data set, appelé SOLUTION1, est créé à partir du fichier CONTRATS.

Créer une nouvelle variable TEL : SAS créé une nouvelle variable TEL.

  • Nombre de contrats par client : Pour chaque ligne d’observation, SAS multiplie le nombre de contrat par la variable binaire TEL pour retrouver le nombre de contrats téléphonique par client.
a 5 1 0 => 5*1 = 5
b 1 1 0 => 1*1 = 1
c 2 0 1 => 2*0 = 0
d 1 1 0 => 1*1 = 1
e 3 0 1 => 3*0 = 0
f 2 1 0 => 2*1 = 2
  • Puis, il fait la somme de tous les nombres (5+1+0+1+0+2) pour connaître le nombre total de contrats téléphoniques. Ce nombre est répété pour chaque observation.
a 5 1 0 => 9
b 1 1 0 => 9
c 2 0 1 => 9
d 1 1 0 => 9
e 3 1 0 => 9
f 2 0 1 => 9

Créer une nouvelle variable HABITAT : De la même manière, une nouvelle variable HABITAT est créée.

  • Nombre de contrat par client : Pour chaque ligne d’observation, SAS multiplie le nombre de contrats par la variable binaire HABITAT pour retrouver le nombre de contrats liés à l’habitation par client.
a 5 1 0 => 5*0 = 0
b 1 1 0 => 1*0 = 0
c 2 0 1 => 2*1 = 2
d 1 1 0 => 1*0 = 0
e 3 0 1 => 3*1 = 3
f 2 1 0 => 2*0 = 0
  • Nombre total de contrats : Puis, il fait la somme de tous les nombres (0+0+2+0+3+0) pour connaître le nombre total de contrats d’habitation. Ce nombre est répété pour chaque observation.
a 5 1 0 => 5
b 1 1 0 => 5
c 2 0 1 => 5
d 1 1 0 => 5
e 3 0 1 => 5
f 2 1 0 => 5

Ne souhaitant pas afficher le nom des clients (variable CLIENT), il est possible d’extraire une seule ligne pour les nouvelles variables TEL et HABITAT en ajoutant le mot-clé DISTINCT. Comme toutes les lignes ont les valeurs 9 et 5, une seule sera conservée.

proc sql;
   create table solution1 as
      select distinct sum(nb_cntr*tel) as tel,
                      sum(nb_cntr*habitat) as habitat
      from contrats;
quit;

Je vous donne rendez-vous tous les lundi pour présenter une nouvelle solution à commencer par lundi prochain dans une étape data, basée sur la notion de variable compteur générée à partir d’un RETAIN.

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

Copier la structure d’un data set et se séparer des données

octobre 16, 2008

Sous SAS, comment récupérer les caractéristiques d’un data set dans un autre data set sans les données et ainsi s’épargner un travail occasionnel mais qui peut vite devenir fastidieux ? Le nom des variables, leur position dans le data set et leurs autres attributs (type, longueur, format, informat) forme la structure d’un data set. Pour les récupérer, deux notations sont offertes : l’option OBS= dans une étape data et le mot LIKE dans une procédure SQL.

1. Créer le data set servant d’exemple

Pour illustrer les deux notations, nous partirons d’un data set nommé CLASS contenant une ligne d’observations et trois variables :

  • le nom de l’élève (NAME),
  • la date de début du cursus (SDT pour starting date) et
  • la date de fin du cursus (EDT pour ending date).

data class;
attrib name length=$15 label=‘Nom’
sdt informat=date9. format=date9. label=‘Starting Date’
edt informat=date9. format=date9. label=‘Ending Date’;
input name $ sdt edt;
datalines;
Charline 06OCT2006 15JUN2007
;
run;

Un PROC CONTENTS résumera les attributs des variables de la manière suivante :

proc contents data=class;
run;

# Variable Type Len Pos Format Informat Label

3 edt Num 8 8 DATE9. DATE9. Ending Date
1 name Char 15 16 Nom
2 sdt Num 8 0 DATE9. DATE9. Starting Date

1. Créer un data set vide

Dans cette première partie, un data set SQL_SOLUTION et ETAPE_DATA sont créés. Les deux ont la même structure

La procédure SQL : Au lieu de désigner toutes les variables à garder après un AS SELECT, on passe directement au data set de référence en l’introduisant avec le mot LIKE.

proc sql;
create table sql_solution like class;
quit;

L’étape data : L’option data set OBS= sur le fichier d’entrée précise qu’aucune observation ne sera lue. Seul le ‘header’ du data set contenant les caractéristiques sont lues par SAS et sauvegardées dans le data set de sortie ETAPE_DATA.

data etape_data;
set class (obs=0);
run;

SAS ira un peu plus vite avec une instruction STOP.

data etape_data;
set class;
stop;
run;

3. Ajouter des observations au data set vide

Une fois le data set copié sans les observations deux lignes sont ajoutées. La première désigne Jean-Pierre qui a début en janvier 2006. Christophe est nommé en second. Il a début le 7 octobre 2005 et terminé le 18 juin 2007.

La procédure SQL : Dans la PROC SQL, je vous propose d’ajouter les observations manuellement grâce à l’instruction INSERT INTO.

proc sql;
create table sql_solution like class;
insert into sql_solution
set name=‘Jean-Pierre’, sdt=’10JAN2006′d
set name=‘Christophe’, sdt=’07OCT2005′d, edt=’18JUN2007′d;
quit;

L’étape data : Dans un data step, les nouvelles observations sont sauvegardées dans un autre data set et sont ajoutées au moyen de l’instruction SET.

data add;
name=‘Jean-Pierre’;
sdt=’10JAN2006′d;
output;
name=‘Christophe’;
sdt=’07OCT2005′d;
edt=’18JUN2007′d;
output;
run;

data etape_data;
set class (obs=0)
add;
run;

Note : Dans ce cas, il faut que le data set contenant la structure apparaissent en premier. SAS sauvegarde toujours la première variable qu’il rencontre avec ses attributs. Proposer une autre variable du même nom avec des attributs différents ensuite n’alternera pas celles sauvegardées en premier.

h1

Renommer une variable (RENAME)

octobre 14, 2008

Pour renommer une variable SAS dispose d’une option RENAME applicable dans une étape data et dans une procédure. De plus, l’instruction RENAME de l’étape data et le mot-clé AS de la PROC SQL sont disponibles. Voici donc une présentation de ces différentes notations.

La base des exemples :

Pour illustrer le propos, le data set CLASS de la bibliothèque SASHELP aura deux variables à renommer : la variable NAME deviendra la variable NOM et la variable HEIGHT s’appellera TAILLE.

Une observation seulement sera gardée : celle concernant ‘Barbara’. Selon que les variables sont renommées dans le fichier d’entrée ou le fichier de sortie, la variable NAME ou NOM sera utilisée pour définir la condition.

Quel ordre ? : Qu’il s’agisse d’une option ou d’une instruction RENAME, il faut utiliser le signe égal (=) avec :

  • en premier, à gauche le nom actuel de la variable
  • en dernier, à droite le nouveau nom.

Pour s’en souvenir, vous pouvez imaginer une forme de flèche. A=>B symbole alors variable A donne/devient variable B).

1. Les options du data step en solitaire

Après avoir donné le nom d’un data set dans une étape data ou dans une procédure comme PROC SORT ou PROC TRANSPOSE, il est possible de lister des options entre parenthèses parmi lesquelles on trouve RENAME. L’option s’applique donc au data set nommé juste avant.

Dans une étape data, il est possible d’appliquer l’option RENAME sur les data sets à lire ou sur les data sets créés. Voici deux exemples avec des instructions SET. Cela marche aussi avec d’autres instructions nommant un data set comme MERGE.

Dans ce premier exemple, les variables NAME et HEIGHT du data set d’entrée (SASHELP.CLASS) sont renommées. Une fois cela fait, SAS effectue les étapes suivantes à savoir garder les observations se référant à Barbara. C’est pour cela que la condition s’applique sur la variable NOM.

data opt_in;
set sashelp.class (rename=(name=nom height=taille));
if nom=‘Barbara’ then output;
run;

Dans ce second exemple, l’option RENAME est appliquée sur le fichier de sortie. La condition est donc traitée par SAS avant que les variables soient renommées. Il faut désigner la variable avec son nom d’origine (NAME) dans la condition.

data opt_out (rename=(name=nom height=taille));
set sashelp.class;
if name=‘Barbara’ then output;
run;

Les deux data sets OPT_IN et OPT_OUT donnent le même fichier final.

nom Sex Age taille Weight

Barbara F 13 65.3 98

2. Les procédures

De la même manière, l’option RENAME peut s’appliquer sur le fichier d’entrée (sauf PROC SQL) et de sortie d’une procédure. Voici deux exemples avec les procédures PROC SORT et PROC SQL.

proc sort data=sashelp.class
out=class (rename=(name=nom height=taille));
by age;
run;

proc sql;
create table opt_out (rename=(name=nom height=taille)) as
select *
from sashelp.class;
quit;

La procédure SQL dispose du mot-clé AS pour renommer une variable en particulier parmi celles énumérées.

proc sql;
create table sql_as as
select name as nom, sex, age, height as taille, weight
from sashelp.class;
quit;

3. L’instruction RENAME du data step

Il existe une instruction RENAME s’appliquant uniquement à l’étape data. Il est important dans ce cas particulier de se rappeler que les variables sont renommées seulement une fois le data set final (INSTRUCT) créé. Le processus de SAS est donc le même qu’avec l’option sur le fichier OPT_OUT.

data instruct;
set sashelp.class;
rename name=nom height=taille;
if name=‘Barbara’ then output;
run;

4. L’option RENAME combinée avec d’autres options du data step

L’option RENAME n’est qu’une des options du data set SAS. Parmi les autres options les plus courantes, citons KEEP, DROP, WHERE, FIRSTOBS et OBS.

Dans ce dernier exemple, on pourra remarquer que l’option WHERE utilise la variable sur l’âge une fois celle-ci renommée. Tandis que l’option KEEP désigne la variable âge d’origine.

data class;
set sashelp.class (keep=age where=(_age=12) rename=(age=_age));
run;

h1

Mon petit doigt me dit que… le mot commence en position 2 (Fonction INDEX)

octobre 10, 2008

Pour savoir si un mot est présent dans une chaîne de caractère, il y a la fonction INDEX. Celle-ci retourne la position d’un « mot » dans une chaîne de caractère. Parmi les fonctions qui lisent les observations textuelles sous SAS, la fonction INDEX fait probablement partie du top 10 des fonctions les plus usuelles.

1. Deux paramètres de base

La chaîne de caractères à analyser est le premier paramètre de la fonction INDEX. Comme toute fonction, elle définie au choix par :

  • le texte entre guillemets
  • la variable caractère contenant toutes les observations à traiter.

Le texte à trouver est le second paramètre de la fonction INDEX. On le donne généralement entre  guillemets.

2. Que retourne la fonction ?

La fonction retourne un nombre : le nombre généré par la fonction INDEX représente la position de la première lettre du mot recherché. Si plusieurs mots sont disponibles dans la chaînes, SAS s’arrête au premier.

Et si aucun mot n’est présent ? Dans le cas où le mot n’est trouvé, la fonction INDEX retourne la valeur zéro. Ainsi si INDEX retourne une valeur supérieure à zéro, le mot est présent dans la chaîne de caractère, sinon il est absent.

3. Minuscules ou majuscules

La lettre A (majuscule) et a (minuscule) ne sont pas identiques. La fonction est sensible à la case.

Si la case de la chaîne de caractère vous importe peu, considérez la chaîne de caractères mise en majuscule (par exemple) avec la fonction UPCASE.

4. Un exemple

Dans l’exemple ci-dessous, le data set ONE a une ligne d’observation et trois variables X, Y et Z.

La variable Y retourne la position du mot ‘de’ (minuscule) dans la chaîne de caractères ‘ABC def DEG’. Il s’agit donc de la position 5.

La variable Z retourne la position du mot ‘DE’ (majuscule) dans la chaîne de caractères ‘ABC def DEG’. Il s’agit donc de la position 9.

data one;
x=‘ABC def DEG’;
y=index(x,’de’);
z=index(x,’DE’);
run;

h1

Supprimer un data set SAS en 6 points (PROC DATASETS)

octobre 6, 2008

Supprimer un data set SAS est une des fonctionnalités de la procédure PROC DATASETS. Voici donc quelques détails sur la syntaxe.

Les options de l’instruction PROC DATASETS donnent la possibilité de supprimer, dans une bibliothèque donnée, tous les fichiers sans distinction de nom (KILL). Certains options réduisent la sélection à certains types de fichiers (MEMTYPE). L’affichage par défaut dans les fenêtres OUTPUT et LOG est contrôlable avec d’autres options (NOLIST et NOWARN). Pour ajouter un peu de flexibilité, il est possible de nommer les fichiers à supprimer ou à garder dans des instructions complémentaires (DELETE et SAVE).

1. Un option pour supprimer tous les fichiers quelque soit leur nom, KILL : Pour supprimer tous les fichiers SAS contenu dans une bibliothèque temporaire, il suffit d’ajouter l’option KILL à l’instruction PROC DATASETS.

2. Par défaut, supprimer tous les types de fichiers MEMTYPE=ALL : En effet, l’option MEMTYPE est par défaut égale à tout (MEMTYE=ALL). Cela comprend 3 types de fichiers :

  • data sets (MEMTYPE=DATA),
  • vues (MEMTYPE=VIEW) ou
  • catalogues (MEMTYPE=CATALOG),

Cela veut dire que les formats, qui sont toujours sauvegardés dans un CATALOG, sont également supprimés.

3. Par défaut, supprimer les fichiers de la bibliothèque temporaire, LIB=WORK : De plus, par défaut, la bibliothèque est temporaire (LIB=WORK) est concernée.

Un premier exemples : Les deux procédures suivantes donnent le même résultat.

proc datasets kill;
quit;

proc datasets lib=work
memtype=all
kill;
quit;

4. Supprimer l’affichage dans la fenêtre OUTPUT avec l’option NOLIST : Pour éviter un affichage dans la fenêtre OUTPUT, vous pouvez ajouter l’option NOLIST ou encadrer la procédure entre deux instructions ODS :

  • ODS LISTING CLOSE : stopper la redirection par défaut vers la fenêtre OUTPUT
  • ODS LISTING : réactiver la redirection vers la fenêtre OUTPUT

5. Désigner les fichiers à garder ou supprimer par leur nom

Deux instructions, soit DELETE, soit SAVE permettent de se concentrer sur quelques fichiers en particulier à supprimer ou non quand l’option KILL n’est pas présente.

Si le type d’un fichier est différent de la majorité des fichiers listés dans l’instruction DELETE (ou SAVE), le type est à définir entre parenthèse avec le mot-clé MEMTYPE= après son nom.

Un second exemple en deux parties

Dans l’exemple qui suit, deux formats  (GENDER et GRP) créés dans la bibliothèque SASREF et tous les data sets de la bibliothèque SASHELP incluant le data set CLASS y sont également copiés.

libname sasref ‘C:/sasref/blog’;

proc format lib=sasref;
value gender 1=‘Male’
2=‘Female’;
value grp    1=‘Per Protocol (PP)’
2=‘Intent to Treat (ITT)’
3=‘Safety’;
run;

proc copy in=sashelp out=sasref memtype=data;
run;

Par défaut, tous les data sets listés dans l’instruction DELETE sont supprimés. A cela s’ajoute le catalogue contenant le format GRP. Il restera donc le format GENDER et tous les data sets sauf CLASS dans la bibliothèque SASREF.

proc datasets lib=sasref
memtype=DATA;
delete class grp (memtype=catalog);
run;

6. Supprimer un fichier qui n’existe pas

Dans certains cas, le nom des fichiers créés dans un programme varie. A la phase de suppression, le fichier manquant sera assortie d’une note dans la LOG:

NOTE: The file SASREF.GENDRE (MEMTYPE=CATALOG) was not found but appear on a DELETE statement.

Deux options s’offrent à vous pour l’éviter :

  • Ajouter l’option NOWARN : dans l’instruction PROC DATASETS, l’option empêchera l’affichage de la note sur les fichiers manquants.
  • Exécuter l’instruction conditionnellement : identifier les fichiers à supprimer au préalable via les dictionnaires et les stocker dans une macro variable.

NOTE : Sachez que PROC COPY a son équivalent dans la procédure PROC DATASETS. Cela dépasse cependant l’objet de cet article.

h1

Trier les données par ordre croissant et décroissant

septembre 23, 2008

Pour trier (to sort en anglais) les données d’un tableau SAS dans un ordre croissant ou décroissant, il existe sous SAS deux approches : la première consiste à faire appel à la procédure PROC SORT sur un data set existant, la seconde consiste à ordonner les données sélectionnées dans une procédure PROC SQL.

1. L’exemple

Dans l’exemple ci-dessous, les données du data set CLASS situé dans la bibliothèque SASHELP sont triées selon les valeurs des variables SEX, AGE et NAME.

  1. Variable SEX, ordre croissant : Les données de la variable SEX sont d’abord triées par ordre croissant (increasing order). Les femmes (F pour Female) apparaissent en premier, les hommes (M pour Male) apparaissent en second.
  2. Variable AGE, ordre décroissant : Dans chacun des groupes, les données sont ensuite triées par ordre décroissant d’âge (descreasing order). Les femmes les plus âgées apparaissent en premier et les hommes les plus jeunes en dernier.
  3. Variable NAME, ordre décroissant : Enfin quand plusieurs personnes du même sexe et du même âge appaissent, les données sont triées par ordre alphabétique inverse.

2. Trier par ordre décroissant

Deux mots-clés différents : Pour trier les données par ordre décroissant, chaque variable doit être accompagnée d’un mot-clé. Il s’agit de DESCENDING avec PROC SORT et DESC avec PROC SQL.

Deux mot-clés situés à des endroits différents : Dans le cas de PROC SORT, ce mot DESCDENDING apparaît avant le nom de la variable. Dans le cas de la PROC SQL, DESC suit la variable

3. La procédure PROC SORT

Les data sets de la bibliothèque SASHELP sont des données figées par SAS. Elles ne peuvent donc pas être modifiées. C’est pourquoi dans l’exemple, un nouveau data set CLASS est créé dans la bibliothèque WORK grâce à OUT=.

proc sort data=sashelp.class out=class;
by sex descending age descending name;
run;

Un PROC PRINT suffira pour afficher les trois variables ou toutes les variables triées. NOOBS enlèvera le numéro des observations qui appraissent par défaut.

proc print data=class noobs;
*var sex age name;
run;

4. La procédure SQL

proc sql;
select sex, age, name
from sashelp.class
order by sex, age desc, name desc;
quit;

Rappel : Pour afficher toutes les variables remplacées la liste de SELECT par une étoile (*). Pour créer un data set, ajoutez CREATE TABLE class AS.

5. Le résultat

sex  age  name

F   15   Mary
F   15   Janet
F   14   Judy
F   14   Carol
F   13   Barbara
F   13   Alice
F   12   Louise
F   12   Jane
F   11   Joyce
M   16   Philip
M   15   William
M   15   Ronald
M   14   Henry
M   14   Alfred
M   13   Jefrrey
M   12   Robert
M   12   John
M   12   James
M   11   Thomas

h1

4 étapes de base pour créer un data set avec PROC SQL

septembre 18, 2008

La procédure SQL disponible sous SAS est une alternative à l’étape data (data step en anglais) dans de nombreuses situations. La syntaxe est dérivée du langage SQL abbréviation de Structured Query Language. Il s’agit donc de faire une requête (query) auprès de SAS pour extraire une information à partir d’un ou plusieurs jeux de données.

Voici donc ici l’occasion de voir la syntaxe de base pour créer un data set à partir d’un autre data set.

1. Début et fin : les instructions PROC SQL et QUIT.

Pour débuter une procédure SQL, il faut taper une instruction commençant par PROC SQL et finir avec une instruction QUIT (et non RUN). Entre ces deux instructions, une nouvelle instruction créera le nouveau data set.

Il est possible d’avoir autant d’instructions entre PROC SQL et QUIT que voulu. Dans la suite, seul un data set sera créé. Il n’y aura q’une seule instruction.

proc sql;
*instruction 1: créer un premier data set par exemple;
*instruction 2 : créer un second data set par exemple;

quit;

2. Lister les variables après SELECT

Un mot introductif, SELECT : l’instruction centrale débute avec le mot-clé SELECT. A la suite figurent toutes les variables à garder.

La virgule comme délimiteur : A la différence d’un data step, la procédure SQL utilise la virgule et uniquement la virgule comme délimiteur entre les noms de variables.

proc sql;
select age, height, weight
from sashelp.class;
quit;

Renommer une variable avec AS : Au stade de la sélection des variables, il est possible d’assigner un nom différent de celui d’origine en se servant du mot AS.

Dans l’exemple ci-dessous, la variable d’origine s’appelle HEIGHT. Après cette variable s’appelle TAILLE.

proc sql;
select height as taille
from sashelp.class;
quit;

Ajouter des attributs : Dans un data step, les instructions ATTRIB, LABEL, FORMAT, INFORMAT et LENGTH sont disponibles pour définir les attributs d’une variables. Avec PROC SQL, les attributs sont à donner après le nom de chaque variable.

Exemple : Dans cet exemple, toutes les variables reçoivent un label. De plus, la longueur des variables NAME (caractère) et AGE (numérique) sont redéfinies.

proc sql;
select name length=15 label=‘Nom’,
age length=4,
height label=‘Taille’,
weight label=‘Poids’
from sashelp.class;
quit;

Note : Dans un data step, un symbole dollar ($) est obligatoire pour définir la longueur des variables caractères, alors qu’avec PROC SQL, ce symbole n’est pas demandé.

Lister toutes les variables : pour lister toutes les variables du data set source rapidement, le symbole étoile (asterik) fera le travail. Rien n’empêche d’ajouter d’autres variables à la suite.

Exemple : Dans l’exemple ci-dessous, toutes les variables du data set CLASS situé dans la bibliothèque SASHELP sont gardées. De plus, pour chaque observation, une variable EXTRA prend la valeur ‘TEST’.

proc sql;
select *, ‘TEST’ as extra
from sashelp.class;
quit;

3. Définir le data set source avec le mot-clé FROM

Dans chacun des exemples ci-dessus, un data set source a été introduit pas le mot-clé FROM.

4. Assigner un nom de data set avec CREATE

Par défaut aucun data set n’est créé : Avec un data step, il faut dans un premier temps créer le data set pour pouvoir ensuite l’imprimer. Avec PROC SQL, les informations sont automatiquement envoyées dans la fenêtre de destination (OUTPUT par exemple) si aucun nom de data set n’est donné avant la sélection des variables.

La structure de début de l’instruction centrale : Pour donner un nom de data set, il faut commencer l’instruction centrale par :

CREATE TABLE mon_nom_de_table AS…

Pourquoi un mot-clé TABLE ? : La présence du mot-clé TABLE se justifie par le fait que SAS est capable de créer plusieurs types de fichiers : les SAS data sets appelés aussi TABLE, et les VIEW. Pour débuter seules les TABLES nous intéressent, l’usage des VIEW étant beaucoup plus occasionnel.

Par ailleurs, sachez que les options du data set vues dans un data step (DROP, KEEP, RENAME, WHERE…)  s’appliquent également dans la PROC SQL mais seulement une fois le nouveau data set créé. Pour les curieux, il y a l’article « Je garde ou je jette ? les variables« .

proc sql;
create table class (drop=age) as
select *, ‘TEST’ as extra
from sashelp.class;
quit;

Depuis la version SAS 9, SAS demande explicitement d’éviter de créer un data set portant le même nom que le data set source. Si vous le faites, un message apparaîtra dans la log.

WARNING: This CREATE TABLE statement recursively references the target table. A consequence of this is a possible data integrity problem.

h1

Quel format a la pole position? (FMTSEARCH)

septembre 13, 2008

Sous SAS, les formats appliqués à une variable servent, entre autres, à rendre une information un peu plus compréhensible par l’oeil humain. Ces formats peuvent provenir de plusieurs sources. Il est important de savoir laquelle est privilégiée si plusieurs locations contiennent le même nom de format avec le même type (pour variable caractère ou numérique). L’option globale FMTSEARCH se charge de définir l’ordre privilégié.

Les sources disponibles : Par défaut, SAS dispose d’une série de formats (Liste disponible sur la documentation en ligne). L’utilisateur peut lui aussi créer ses propres formats sauvegardés de manière temporaire (dans la bibliothèque WORK) ou permanent (dans des bibliothèques définies par lui-même).

Exemple d’application : vous pouvez définir des formats communs à tous vos projets. Si un projet est particulier, vous pourrez définir un autre format portant le même nom que celui plus globale et demander qu’il soit privilégié.

Rappel : Pour revoir quelques notions de base sur les formats vous pouvez consultez ces trois articles:

Dans cet article, la notion de bibliothèque est requise. Vous pouvez vous reporter à l’article suivant si vous débutez :

1. Par défaut, il y a deux bibliothèques disponibles

La procédure affiche dans la log la valeur prise par les options globales. L’option OPTION réduit l’affichage à la seule option FMTSEARCH.

proc options option=fmtsearch;
run;

Il apparaît alors que les deux bibliothèques considérées par SAS sont WORK en priorité et les formats standards de SAS en second.

FMTSEARCH=(WORK LIBRARY)
List of catalogs to search for formats and informats

En exécutant l’instruction OPTIONS ci-dessous, l’ordre de priorité est changé.

options fmtsearch(library work);

Après une nouvelle exécution de la procédure PROC OPTIONS, le programmeur peut visualiser le changement.

Voir le résultat :

proc options option=fmtsearch;
run;

Contenu de la log :

FMTSEARCH=(LIBRARY WORK)
List of catalogs to search for formats and informats

2. Ajouter des bibliothèques

Des formats sauvegardés dans des fichiers catalogues : Les formats sont stockés dans des fichiers appelés FORMAT CATALOG. Il faudra que ces fichiers portent un nom FORMATS et l’extension pour désigner un catalogue.

Assigner la bibliothèque contenant le catalogue : Pour considérer des FORMAT CATALOG permanents définis par l’utilisateur, il faut désigner le chemin d’accès au fichier par un nom de bibliothèque (instruction LIBNAME) et ajouter ce nom dans la bibliothèque dans la liste de FMTSEARCH.

Exemple : Dans l’exemple qui suit, un format nommé GENDER est sauvegardé dans le fichier FORMATS.CATALOG au niveau de C:/SASREF, chemin pointé par la bibliothèque SASREF.

libname sasref ‘C:/sasref’;

proc format lib=sasref;
value gender 1=‘MALE’
2=‘FEMALE’;
run;

Puis ce format aura la priorité sur tout autre format GENDER créé de manière temporaire.

options fmtsearch=(sasref work library);

Voir le résultat :

proc options option=fmtsearch;
run;

Contenu de la log :

FMTSEARCH=(SASREF WORK LIBRARY)
List of catalogs to search for formats and informats

3. Important : La priorité de la bibliothèque WORK en cas d’omission.

Les deux exemples suivant donnent le même résultat car la bibliothèque temporaire est mise en priorité si elle n’est pas citée.

options fmtsearch=(work sasref library);
options fmtsearch=(sasref library);

WORK n’est pas ignoré comme pourrait le suggérer l’affichage dans la log ou mise en dernier.

Voir le résultat :

proc options option=fmtsearch;
run;

Contenu de la log :

FMTSEARCH=(SASREF LIBRARY)
List of catalogs to search for formats and informat

h1

Scanner une chaîne de caractère et extraire le xème mot

septembre 12, 2008

Scanner le contenu d’un texte et identifier le xème « Mot » est possible sous SAS grâce à la fonction SCAN. Je vous propose dans un premier temps de voir les différents paramètres de la fonction. Puis dans un second temps, vous aurez à disposition quelques exemples documentés à tester soi-même.

Deux exemples d’applications :

  • Définir une condition (IF THEN par exemple) selon la valeur prise par le mot trouvé.
  • Sauvegarder le « mot » dans une nouvelle variable.

1. Trois paramètres pour la fonction SCAN

La fonction SCAN est composée de trois paramètres.

  1. Le texte à scanner
  2. La position du mot recherché
  3. Le symbole délimitant les mots dans le texte

1.1 Le texte à scanner est donné dans le premier paramètre

Le texte à scanner peut-être une chaîne tapée manuellement entre guillemets. Mais il est plus probable que vous souhaitiez opérer l’opération pour chacune des observations contenues dans une variable caractère.
Il s’agit alors de nommer la variable.

Rappel : lorsqu’une variable est nommée, il ne faut jamais mettre son nom entre guillemets. La fonction SCAN ne fait pas exception.

1.2 La position du mot recherché est définie dans le second paramètre

Des nombres entiers : la position du mot est donnée par un nombre entier.

  • 1 correspond au premier mot de la chaîne de caractères;
  • 2 au deuxième, etc.

Les valeurs négatives : il est en effet possible d’utiliser des valeurs négatives pour définir la position du mot. De quoi s’agit-il ? Tout simplement, au lieu de commencer par le début de la chaîne, SAS commence par la fin.

  • -1 correspond au dernier mot,
  • -2 à l’avant dernier mot, etc.

1.3 Le délimiteur apparaît en troisième

Trouver des « mots » au sens large du terme : En langage courant, un mot est un ensemble de lettres séparées par un espace. Avec la fonction SCAN, le symbole séparant les mots est libre. L’utilisateur se chargera de définir ce symbole.

Le symbole séparant les mots est à donner entre guillemets. A titre d’exemple, il peut s’agir de tirets bas (underscore en anglais), de barre inclinée (slash en anglais), de blancs (blank en anglais).

2. La fonction SCAN par l’exemple

Exemple 1 : Dans ce premier exemple, une variable NAME contient 5 observations.

data dict;
   length name $8;
   input name $;
   datalines;
PAT_ID
COUNTRY
REC_ID
VISIT
VISIT_DT
;
run;

Grâce à la première condition, les observations se terminant par _DT sont sauvegardées dans le data set DT_VAR. Il n’y a que la variable VISIT_DT.
Avec la seconde condition, les observations commençant par VISIT_ sont envoyées dans le data set VISIT_VAR.

data dt_var visit_var;
   set dict;
   if scan(name,-1,‘_’)=‘DT’ then output dt_var;
   if scan(name,1,‘_’)=‘VISIT’ then output visit_var;
run;

Exemple 2 : Dans ce second exemple, une variable PATH a 3 observations.

data path_lst;
   path=‘c:/sasref/projet123/study1/pgm’;
   output;
   path=‘c:/sasref/projet123/study9/pgm’;
   output;
   path=‘c:/sasref/projet444/study2/pgm’;
   output;
run;

Dans ce premier cas, les observations contenant le mot proj123 en troisième niveau dans le chemin d’accès sont gardées.

data projet123;
   set path_lst;
   if scan(path,3,‘/’)=‘projet123’;*then output;
run;

Dans ce second cas, une nouvelle variable est créée. Elle contient le numéro de l’étude disponible en quatrième position dans le chemin d’accès fourni dans la variable PATH.

data study_var;
   study=scan(path,4,‘/’);
run;

Je vous donne rendez-vous demain samedi pour un article sur l’option FMTSEARCH.

h1

Je garde ou je jette? les variables

août 25, 2008

Pour garder ou supprimer sous SAS des variables, il y a les mots-clés KEEP (garder) et DROP (enlever). Sélectionner les variables nécessaires par la suite et seulement celles-ci est très important. Cela fait partie des outils pour améliorer la performance d’un programme tant en terme de temps d’exécution que le volume demandé pour stocker les data sets. Voici plus en détails, et avec des exemples, l’utilisation de ce vocabulaire qui s’applique au data step, aux procédures et à la syntaxe de l’ODS OUTPUT.

1. L’option dans un data step

Les mots KEEP et DROP servent principalement en tant qu’option appliquée à un data set donné. Elles sont alors listées juste après le nom du data set entre parenthèses et sont suivies du signe égal :

  • Keep= Data Set Option : nom_du_dataset (keep=nom_var1 nom_var2 etc)
  • Drop= Data Set Option : nom_du_dataset (drop=nom_var1 nom_var2 etc)

Exemple 1 : une instruction SET

data class (drop=weight: height:);
   set sashelp.class (keep=name weight height);
   weight_kg = weight*0.45359237;
   height_m  = height*0.0254;
   bmi       = weight_kg/height_m**2;
run;

Dans le cas présent, les variables NAME (nom), WEIGHT (poids) et HEIGHT (taille) sont lues dans le fichier d’origine SASHELP.CLASS et gardées. De nouvelles variables sont calculées pour avoir un poids en kilogramme (WIEGHT_KG) et une taille en mètres (HEIGHT_M). A partir du poids et de la taille, l’indicateur de masse corporelle (BMI) est calculé. Les variables, dont le nom commence par WEIGHT et HEIGHT, ne sont plus nécessaires par la suite. Elles sont donc supprimée dans le data set final appelé CLASS.

Soit le mot KEEP, soit le mot DROP est donné en option mais pas les deux afin d’éviter les confusions. Le choix entre KEEP et DROP dépend souvent du nombre de variables à lister par la suite. C’est donc un choix purement pratique.

Note, Indice de masse corporelle : L’indice de masse corporel (Body Mass Index, BMI) est égal au poids divisé par la taille au carré (poids/taille2). Le site de l’Organisation Mondiale de la Santé (World Health Organisation, WHO) donne des précisions sur le sujet.

Note, Conversion des unités de mesures (source Wikipedia) : je suppose que la taille donnée dans le fichier SASHELP.CLASS est exprimée en pouces (inches) et que le poids est exprimé en livres (pounds). Sachant qu’un pouce est égal à 2,54 cm et qu’une livre est égale à 0,45359237 kg, les tailles et poids du premier exemple ont pu être convertis en mètres et kilos.

Exemple 2 : une instruction MERGE

data age_ae;
   merge ae      (in=ref keep=name ae_id ae_sev)
         patient (keep=name age);
   by name;
   if ref;
run;

Dans ce second exemple, les patients ayant eu un effet secondaire (adverse event, AE) sont enregistrés dans le data set AE. Chaque effet secondaire est identifié de manière unique par les variables NAME et AE_ID. La sévérité de l’effet secondaire nous intéresse dans le data set AE.

A cette information, est ajouté l’âge du patient disponible dans la variable AGE du data set PATIENT.

La variable commune aux deux data sets est NAME. Il faut donc qu’elle reste dans les deux data sets. Seuls les patients ayant eu un effet secondaire sont sélectionnés grâce à l’option IN.

Pour tester l’exemple, vous trouverez en fin d’article un code créant les fichiers PATIENT et AE.

NOTE : Une variable utilisée par une autre option du data set comme RENAME ou WHERE ne pourra pas être supprimée au même moment.

2. Quelques exemples de procédures

Dans une procédure, elles suivent le nom du data set d’entrée et/ou du data set de sortie. Aucun autre mot ne doit être inséré entre le nom du data set et les options entre parenthèses.

  • proc sort data=… () out=…();
  • proc print data=… () width=min;
  • proc transpose data=…() out=…() prefix=visit;
  • proc freq data=…();
  • proc report data=…() split=’#’;
  • proc tabulate data=…()
  • proc gplot data=…()
  • proc boxplot data=…()
  • proc univariate data=…()
  • proc ttest data=…()
  • etc.

La procédure SQL liste les variables à garder après le mot SELECT. Il n’y a pas à ce stade d’option pour supprimer les variables. Par contre, on peut affiner la sélection après que le data set final soit créé. Bien sûr, le temps de lecture est augmenté puisque toutes les variables sont lues pour créer le data set et non un sous-ensemble.

proc sql;
   create table test (drop=ae_sdt ae_edt) as
      select a.*, age
      from ae a
      left join
           patient b
      on a.name=b.name;
quit;

NOTE : L’option WHERE est très pratique lorsqu’on en peut faire une sélection que sur le résultat de la fusion.

proc sql;
   create table test (where=(ae_sev=1 or age=12)) as
      select a.*, age
      from (select name, ae_id, ae_sev
            from ae) a
      left join
           (select name, age
            from patient) b
      on a.name=b.name;
quit;

3. L’option dans l’ODS OUTPUT

Les sorties générées par une procédure sont redirigeables vers un data set via l’instruction ODS OUTPUT. Le nom de la sortie est alors suivi du signe égal et du nom du data set de destination. Après ce nom les options sont ajoutables.

ods exclude all;
ods output onewayfreqs=exemple_ods (keep=age frequency percent);
proc freq data=sashelp.class;
   table age;
run;
ods output clear;
ods exclude none;

Deux articles sur l’ODS OUTPUT sont déjà à votre disposition

4. Les instructions KEEP et DROP dans un data step

En plus des options KEEP et DROP, il existe les instructions KEEP (KEEP Statement) et DROP (Drop Statement) pouvant être exécutées dans un data step. L’important ici est de se souvenir que l’instruction s’applique à la fin du data step, une fois que le data set final est créé. Ainsi il n’est pas possible de supprimer une variable en milieu de programme pour ensuite créer une autre variable du même nom.

data class (drop=i);
   do i=0 to 3;
      output;
   end;
   do i=10 to 12;
      output;
   end;
run;

data class;
   do i=0 to 3;
      output;
   end;
   drop i;
   do i=10 to 12;
      output;
   end;
run;

Les deux exemples ci-dessus font le même travail. La variable I n’apparaîtra pas dans le data set final car elle est supprimée en fin de programme.

Lectures complémentaires : Outre les options KEEP et DROP, le programmeur utilisera souvent les options RENAME et WHERE et de temps en temps les options FIRSTOBS et OBS. Pour une liste complète des options, consultez la documentation en ligne : SAS Data Set Option.

Après savoir comment supprimer les variables et donc les colonnes d’un data set SAS, vous serez peut-être intéressé de savoir comment supprimer ou garder certaines lignes d’un data set avec les mots-clés DELETE (DELETE Statement) et OUTPUT (OUTPUT Statement).

Annexe : Créer les data sets PATIENT et AE pour tester l’exemple avec MERGE.

data patient;
   set sashelp.class;
run;

data ae;
   set sashelp.class (keep=name);
   if name=‘Thomas’ then
      do;
         ae_id  = 1;
         ae_sdt = ’21MAR2007’d;
         ae_edt = ’28APR2007’d;
         ae_sev = 3;
         output;
         ae_id  = 2;
         ae_sdt = ’03JUN2007’d;
         ae_edt = ’19JUN2007’d;
         ae_sev = 1;
         output;
      end;
run;

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

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

Supprimer des formats

août 7, 2008

Après avoir présenté dans l’article « 2 méthodes pour de nouveaux formats » comment créer un format de manières temporaire et permanente, nous allons voir comment les supprimer.

Rappel : les formats SAS sont sauvegardés dans un fichier nommé catalogue pour les formats (format catalog). Il peut exister plusieurs fichiers ayant des noms différents selon l’information donnée lors de la création dans l’option LIB= de PROC FORMAT. Si aucun nom en particulier n’a été donné lors de la création, alors le catalogue pour les formats s’appelle FORMATS et est sauvegardé temporairement dans la bibliothèque WORK.

1. Créer deux formats pour l’exemple

Dans un premier temps, pour illustrer le code, trois formats sont créés dans le catalogue nommé FORMATS de la bibliothèque WORK. Ces formats s’appellent NY, SEX et GENDER. Les deux premiers sont numériques, le troisième s’applique à des variables caractères.

Dans cet exemple les éléments mis en commentaire sont les valeurs implicites, celles que SAS utilise par défaut.

proc format; *lib=work.formats;
   value ny        1 = ‘NO’
                   2 = ‘YES’;
   value sex       1 = ‘Male’
                   2 = ‘Female’;
   value $ gender ‘M’ = ‘Male’
                  ‘F’ = ‘Female’;
run;

2. Supprimer un à un les formats du catalog

Avec la procédure PROC CATALOG, les formats NY et GENDER sont supprimés du catalogue FORMATS. Il restera le format SEX dans le catalogue. Il est impératif ici de nommer le nom du catalogue (FORMATS) et la bibliothèque où il est sauvegardé avec l’option CATALOG=.

Dans l’instruction DELETE figurent le nom des formats à supprimer. Le type d’entrée (entry type ou ET) est à préciser.

  • Dans le premier cas, les formats NY et GENDER sont de type différent. Chacun d’eux est suivi du type de l’entrée entre parenthèses. L’un est numérique (ET=FORMAT) et l’autre est caractère (ET=FORMATC).
  • Si tous les formats listés sont du même type, il est possible d’utiliser l’option ET= après une barre inclinée. Les formats AGE et SEX sont tous les deux numériques. L’option ET=FORMAT suffit.

proc catalog catalog=work.formats;
   delete ny (et=format) gender (et=formatc);
   *delete age sex / et=format;
run;

3. Supprimer le catalogue en entier avec tous ces formats

La procédure PROC DATASETS permet de supprimer un catalogue contenant des formats. Pour se faire, il faut d’abord préciser le type de fichier avec l’option MEMTYPE, la valeur par défaut étant DATA. Par défaut SAS recherchera le catalogue dans la bibliothèque WORK à moins de préciser une autre bibliothèque. Le nom du fichier catalogue contenant les formats est donné dans l’instruction DELETE

proc datasets memtype=catalog;*lib=work;
   delete formats;
run;

Annexe : cet exemple est le même que précédemment à une exception près.

  • D’une part, le format catalogue est maintenant permanent puisqu’il est sauvegardé dans la bibliothèque SASREF et non WORK.
  • D’autre part, il est sauvegardé avec un nom choisi par le programmeur (VERO) et non FORMATS.

libname sasref ‘C:/sasref’;

proc format lib=sasref.vero;
   value ny        1 = ‘NO’
                   2 = ‘YES’;
   value sex       1 = ‘Male’
                   2 = ‘Female’;
   value $ gender ‘M’ = ‘Male’
                  ‘F’ = ‘Female’;
run;

proc catalog catalog=sasref.vero;
   delete ny (et=format);
run;

proc datasets lib=sasref memtype=catalog;
   delete vero;
run;

h1

Un tableau à une dimension avec PROC FREQ et ODS OUTPUT

juillet 31, 2008

Pour personnaliser une sortie statistique générée par une procédure SAS, il faut parfois convertir ses résultats en tableau (SAS data set). Dans un précédent article, la procédure PROC MEANS a été mise à l’honneur (Diriger la sortie d’un PROC MEANS dans un dataset SAS). Maintenant nous abordons la procédure PROC FREQ dans le cadre d’un tableau à une dimension en combinaison avec l’instruction ODS OUTPUT.

1. Identifier le nom des sorties : un exemple avec une variable

ods trace on/listing;

*Exemple 1 : Proc Freq, une variable;
proc freq data=sashelp.class;
   table age;
run;

ods trace off;

On obtient deux types de tables selon qu’il s’agisse d’un tableau à une dimension ou à plusieurs dimensions.

  • OneWayFreqs: Dans le cas d’un PROC FREQ avec une seule variable, on parle de OneWayFreqs.
  • CrossTabFreqs: Dans le cas d’un tableau croisé, la sortie se nomme CrossTabFreqs.

Output Added:
————-
Name: OneWayFreqs
Label: One-Way Frequencies
Template: Base.Freq.OneWayFreqs
Path: Freq.Table1.OneWayFreqs
————-

1. Identifier le nom des sorties : un exemple avec 2 variables

Dans ce second exemple, deux variables (AGE et SEX)  sont listées. Les statistiques de l’une seront indépendantes des statistiques de l’autre.

ods trace on/listing;

*Exemple 2 : Proc Freq, deux variables;
proc freq data=sashelp.class;
   table age sex;
run;

ods trace off;

Pour distinguer les statistiques de la table SEX de celles de la table AGE, deux outputs sont créés dans la fenêtre OUTPUT. Leur nom (NAME) est identique mais leur chemin d’accès (PATH) varie. On parle de TABLE1 et TABLE2.

Output Added:
————-
Name: OneWayFreqs
Label: One-Way Frequencies
Template: Base.Freq.OneWayFreqs
Path: Freq.Table1.OneWayFreqs
————-

Output Added:
————-
Name: OneWayFreqs
Label: One-Way Frequencies
Template: Base.Freq.OneWayFreqs
Path: Freq.Table2.OneWayFreqs
————-

3. Identifier le nom des sorties : un exemple avec une instruction BY

Avant de se servir d’une instruction BY, les données doivent être triées. La procédure PROC SORT le fait. 

Le data set source est un data set non modifiable. C’est un data set de la bibliothèque SASHELP fournit avec le logiciel SAS.

La version triée est sauvegardée de manière temporaire dans la bibliothèque WORK (bibliothèque par défaut quand son nom n’est pas cité). Ce nouveau dataset s’appelle CLASS.

proc sort data=sashelp.class out=class;
   by sex;
run;

ods trace on/listing;

*Exemple 3 : Proc Freq, une variable et une instruction BY;
proc freq data=class;
   by sex;
   table age;
run;

ods trace off;

Avec une instruction BY, il y a plusieurs outputs pour une seule procédure dans la fenêtre OUTPUT. Les deux sorties ont le même nom (NAME) mais le chemin d’accès (PATH) est différent. On parle de TABLE1 dans les deux cas et de BYGROUP1 et BYGROUP2 pour les distinguer.

Output Added:
————-
Name: OneWayFreqs
Label: One-Way Frequencies
Template: Base.Freq.OneWayFreqs
Path: Freq.ByGroup1.Table1.OneWayFreqs
————-

Output Added:
————-
Name: OneWayFreqs
Label: One-Way Frequencies
Template: Base.Freq.OneWayFreqs
Path: Freq.ByGroup2.Table1.OneWayFreqs
————-

4. ODS OUTPUT et PROC FREQ

L’instruction ODS OUTPUT convertit les sorties dans un data set SAS. Voici donc le résultat de trois PROC PRINT sur les data sets créés avec l’instruction ODS OUTPUT.

4.1 Exemple 1, tableau avec une variable

Dans ce premier exemple, on note, d’une part, la présence de la variable caractère TABLE ; d’autre part, deux variables listent les différentes valeurs prises par la variable AGE : l’une est caractère, l’autre est numérique.

*Exemple 1 : Proc Freq, une variable;
proc freq data=sashelp.class;
   table age;
   ods output onewayfreqs=exemple1;
run;

                                         Cum      Cum
Table     F_Age Age Frequency Percent Frequency Percent

Table Age   11   11     2      10.53       2      10.53
Table Age   12   12     5      26.32       7      36.84
Table Age   13   13     3      15.79      10      52.63
Table Age   14   14     4      21.05      14      73.68
Table Age   15   15     4      21.05      18      94.74
Table Age   16   16     1       5.26      19     100.00

4.2 Exemple 2, tableau avec deux variables

En ajoutant une deuxième variable SEX, des variables supplémentaires sont ajoutées dans la table de sortie. Elles listent les valeurs prises par la variable supplémentaire. Comme précédemment avec la variable AGE, il y a deux variables pour accéder à la fois à l’information sous forme caractère et sous forme numérique a priori. Mais comme ici la variable d’origine est caractère, les deux sont de type caractère.

*Exemple 2 : Proc Freq, deux variables;
proc freq data=sashelp.class;
   table age sex;
   ods output onewayfreqs=exemple2;
run;

                                        Cum      Cum
Table    F_Age Age Frequency Percent Frequency Percent F_Sex Sex

Table Age  11   11     2      10.53        2     10.53
Table Age  12   12     5      26.32        7     36.84
Table Age  13   13     3      15.79       10     52.63
Table Age  14   14     4      21.05       14     73.68
Table Age  15   15     4      21.05       18     94.74
Table Age  16   16     1       5.26       19    100.00
Table Sex        .     9      47.37        9     47.37    F   F
Table Sex        .    10      52.63       19    100.00    M   M

4.3 Exemple 3, tableau avec une instruction BY

Avec l’instruction BY, une seule variable est créée pour distinguer les âges des hommes de ceux des femmes.

*Exemple 3 : Proc Freq, une variable et une instruction BY;
proc freq data=class;
  
by sex;
  
table age;
run;

                                             Cum      Cum
Sex   Table   F_Age Age Frequency Percent Frequency Percent

  Table Age   11   11     1      11.11      1      11.11
 F  Table Age   12   12     2      22.22      3      33.33
 F  Table Age   13   13     2      22.22      5      55.56
 F  Table Age   14   14     2      22.22      7      77.78
 F  Table Age   15   15     2      22.22      9     100.00
 M  Table Age   11   11     1      10.00      1      10.00
 M  Table Age   12   12     3      30.00      4      40.00
 M  Table Age   13   13     1      10.00      5      50.00
 M  Table Age   14   14     2      20.00      7      70.00
 M  Table Age   15   15     2      20.00      9      90.00
 M  Table Age   16   16     1      10.00     10     100.00

NOTE : Dans le cas de l’utilisation de plusieurs PROC FREQ se servant du même OUTPUT (onewayfreqs par exemple), il est conseillé de nettoyer l’ODS OUTPUT avec l’option CLEAR.

ods output clear;

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

Diriger les sorties d’un PROC MEANS dans un dataset SAS

juillet 24, 2008

Par défaut, les résultats des procédures SAS sont affichés dans la fenêtre OUTPUT. Pour convertir ces résultats en tableau SAS (SAS dataset), la syntaxe de l’ODS (Output Delivery System) dispose d’outils appropriés comme les instructions 

  • ODS TRACE pour identifier une sortie,
  • ODS OUTPUT pour rediriger une sortie vers un data set,
  • ODS SELECT and ODS EXCLUDE pour choisir les sorties apparaissant dans la fenêtre OUTPUT.

Pour illustrer ce sujet, la procédure PROC MEANS sera utilisée.

Remise dans le contexte :

  • Changer l’éditeur pour une présentation plus fine : rediriger vers un document RTF avec ODS RTF s’applique une fois que la formulation nous convient.
  • Changer la formulation des informations : le TEMPLATE peut préalablement être modifié pour n’afficher qu’un sous ensemble du résultat par exemple.
  • Faire de gros travaux : pivoter un tableau, combiner des résultats entre eux ou encore calculer une valeur à partir des résultats existant fait partie des gros travaux qui nécessitent de passer par un dataset SAS.

1. Identifier le nom des résultats

Pour voir le nom des différentes outputs, entourez votre procédure des instructions ODS TRACE ON/LISTING et ODS TRACE OFF.

  • La première instruction demande l’affichage de chacune des noms des sorties.
  • L’option LISTING permet d’afficher cette information dans la fenêtre OUTPUT. La destination par défaut est la LOG.
  • Enfin, la seconde instruction désactive le traçage.

Premier exemple

ods trace on/listing;

*Exemple 1 : Proc Means;
proc means data=sashelp.class;
   var height weight;
run;

ods trace off;

On obtient la sortie de PROC MEANS appelée SUMMARY.

Output Added:
————-
Name: Summary
Label: Summary statistics
Template: base.summary
Path: Means.Summary
————-

Second exemple avec une instruction BY : il est toujours possible d’ajouter une instruction BY dans PROC MEANS.

proc sort data=sashelp.class out=class;
   by sex;
run;

ods trace on/listing;

*Exemple 2 : Proc MEANS et l’instruction BY;
proc means data=class;
   by sex;
   var height weight;
run;

ods trace off;

Il y a plusieurs outputs pour une seule procédure. Les deux sorties ont le même nom (NAME) mais le chemin d’accès (PATH) est différent. On parle de BYGROUP1 et BYGROUP2 pour les distinguer.

Output Added:
————-
Name: Summary
Label: Summary statistics
Template: base.summary
Path: Means.ByGroup1.Summary
————-

Output Added:
————-
Name: Summary
Label: Summary statistics
Template: base.summary
Path: Means.ByGroup2.Summary
————-

2. ODS OUTPUT et PROC MEANS

Dans le premier exemple, un data set EXEMPLE1 est créé à partir de la sortie ONEWAYFREQ de la PROC MEANS appliquée au fichier SASHELP.CLASS.

J’ai choisi d’écrire l’instruction ODS OUTPUT à l’intérieur de la procédure puisqu’elle s’applique uniquement à la procédure mais elle peut être aussi affichée avant la procédure.

Une seule instruction pour plusieurs data sets à créer : Ecrire l’instruction ODS OUTPUT avant la procédure est intéressant si vous générez plusieurs sorties de procédures différentes et voulez lister tous les data sets SAS à créer en une seul instruction ODS OUTPUT.

*Exemple 1 : Proc Means;
proc means data=sashelp.class;
   var height weight;
   ods output summary=exemple1;
run;

 
Un fichier brut peu lisible : Après un PROC PRINT sur le data set EXEMPLE1, on découvre un fichier peu lisible dès qu’il y a plus d’une variable.

   VName_          
   Height      Height_N    Height_Mean  

   Height        19        62.336842105  

   Height_
   StdDev      Height_Min  Height_Max

5.1270752466     51.3          72

   VName_
   Weight      Weight_N    Weight_Mean
   Weight        19        100.02631579

  Weight_
   StdDev      Height_Min  Height_Max
22.773933494     50.5          150

Solution, étape 1 : Une solution est de faire un PROC TRANSPOSE pour un résultat sous la forme ci-dessous.

   _NAME_     _LABEL_     COL1

Height_N      N          19.000
Height_Mean   Mean       62.337
Height_StdDev Std Dev     5.127
Height_Min    Minimum    51.300
Height_Max    Maximum    72.000
Weight_N      N          19.000
Weight_Mean   Mean      100.026
Weight_StdDev Std Dev    22.774
Weight_Min    Minimum    50.500
Weight_Max    Maximum   150.000

Dans la sortie brute de l’ODS OUTPUT, les variables commencent soit par HEIGHT, soit par WEIGHT (soit par VNAME ne m’intéresse pas ici). Il s’agit de transposer toutes ces variables. Il faut donc toutes les lister. Par soucis de clarté et de simplicité, on peut faire appel à une version abrégée : la racine commune des variables suivie de deux points.

proc transpose data=exemple1 out=exemple1;
   var height: weight:;
run;

Solution, étape 2 : Pour retrouver une présentation semblable à celle d’un PROC MEANS envoyé dans la fenêtre OUTPUT, il faut transposer de nouveau. Auparavant, il faut créer une variable distinguant la variable HEIGHT de la variable WEIGHT.

var_name  N   Mean   Std_Dev Minimum Maximum

 Height  19  62.337  5.1271    51.3     72
 Weight  19 100.026 22.7739    50.5    150

Créer une variable nommée VAR_NAME prenant soit la valeur HEIGHT soit la valeur WEIGHT.

  • La fonction SCAN récupérera, dans une variable nommée VAR_NAME, le premier mot de la variable _NAME_ après avoir précisé que chaque mot est séparé par un trait bas (underscore).
  • La longueur de la variable est définie explicitement au cas où certains noms de variables seraient supérieurs à 8 et donc tronqués.
  • Cette longueur est définie avant l’instruction SET pour que la variable VAR_NAME apparaisse en premier.

data exemple1 (drop=_name_);
   length var_name $12;
   set exemple1;
   var_name=scan(_name_,1,‘_’);
run;

Il est alors possible de faire pivoter le data set. Une ligne est créée pour HEIGHT et une autre pour WEIGHT, c’est-à-dire pour chaque nouvelle valeur de VAR_NAME. Chaque colonne prend le nom contenu dans la variable _LABEL_.

proc transpose data=exemple1 out=exemple1 (drop=_name_);
   by var_name;
   id _label_;
run;

L’instruction BY : Dans le cas du PROC MEANS, on ne rencontre pas de difficulté particulière liée à l’instruction BY. Au lieu d’avoir une ligne dans le fichier de sortie, on a autant de lignes que de valeurs dans la variable de l’instruction BY. Dans notre exemple, on a donc deux lignes avec une instruction BY SEX. Vous pouvez retrouver le code pour la transposition en fin d’article pour obtenir la sortie suivante :

Sex=F

var_name  N   Mean  Std_Dev Minimum Maximum

 Height   9 60.5889  5.0183   51.3    66.5
 Weight   9 90.1111 19.3839   50.5   112.5

Sex=M

var_name  N  Mean  Std_Dev Minimum Maximum

 Height  10  63.91  4.9379    57.3    72
 Weight  10 108.95 22.7272    83.0   150

3. Sélectionner ou exclure certaines sorties ou toute les sorties (ODS EXCLUDE, SELECT, LISTING)

L’instruction ODS LISTING CLOSE suspend l’envoie de toutes les sorties dans la fenêtre OUTPUT. L’ODS EXCLUDE interrompt un sous-ensemble ou toutes les sorties générées par la procédure. A l’inverse, l’ODS SELECT retient les sorties. A vous de voir si vous avez plus vite fait de lister les sorties à garder ou celles à exclure.

Quelques sorties : Pour sélectionner ou exclure quelques sorties en particulier, il suffit d’ajouter leur nom, trouvés au préalable avec ODS TRACE ON, séparé par un espace dans l’instruction. Cela est pratique pour des procédures générant beaucoup de sorties comme PROC UNIVARIATE. 

Toutes les sorties : Pour faire la même chose sur toutes les sorties, on utilise ALL et NONE avec ODS EXCLUDE et ODS SELECT.

*Exemple 1 : Proc Means;

ods exclude all; *ods select none; *ods listing close;
proc means
data=sashelp.class;
   var height weight;

   ods output summary=exemple1;
run;
ods exclude none; *ods select all; *ods listing;

Note : Toutes les explications couvertes dans cet article s’appliquent aussi à la procédure PROC SUMMARY.

Annexe : Détails du programme s’appliquant au second exemple

*Exemple 2 : Proc MEANS et l’instruction BY;

proc sort data=sashelp.class out=class;
   by sex;
run;

proc means data=class;
   by sex;
   var height weight;
   ods output summary=exemple2;
run;

proc transpose data=exemple2 out=exemple2;
   by sex;
   var height: weight:;
run;

data exemple2 (drop=_name_);
   length var_name $12;
   set exemple2;
   var_name=scan(_name_,1,‘_’);
run;

proc transpose data=exemple2 out=exemple2 (drop=_name_);
   by sex var_name;
   id _label_;
run;

proc print data=exemple2 noobs;
   by sex;
run;

h1

2 suggestions pour grouper les valeurs d’une variable

juillet 21, 2008

Sous SAS, lorsqu’une variable contient plusieurs valeurs à regrouper pour n’en former qu’une seule, il existe plusieurs options. Voici deux suggestions : une basée sur la notion de RETAIN et FIRST/LAST, l’autre sur PROC TRANSPOSE et ARRAY.

Pour illustrer le propos un data set liste plusieurs actions pour un patient à une visite donnée. Il s’agit de regrouper ces actions par patient et visite dans un seul record.

Le data set avant

pat_id  visit_dt rec_id action

   1   02APR2007    1   RAYON X
   1   02APR2007    2   ULTRASON
   1   02APR2007    3   SCANNER
   2   15NOV2007    2   RAYON X
   2   15NOV2007    1   ULTRASON

Le data set après : une nouvelle variable caractère est créée ACTION_LST. On lui donnera une longueur de 200. Chaque action y est séparée par une barre. Les variables REC_ID (identifiant du record) et ACTION sont supprimées.

pat_id  visit_dt action_lst

   1   02APR2007 RAYON X | ULTRASON | SCANNER
   2   15NOV2007 ULTRASON | RAYON X

1. La force du RETAIN

Pour débuter une variable ACTION_LST de longueur 200 est créée. Elle ne contient à la base aucune valeur.

data final; *(drop = rec_id action);
   set orig;
   by pat_id visit_dt;
   length action_lst $200;
   retain action_lst ‘ ‘;
   if first.visit_dt then action_lst=action;
   else action_lst=catx(‘ | ‘,action_lst,action);
   *if last.visit_dt then output;
run;

Pour chaque nouvelle visite de chaque patient, ACTION_LST est initialisée. Elle prend la valeur de la variable ACTION.

Du fait de la présence de l’instruction RETAIN, cette première valeur est maintenue pour tous les records d’une même visite. A chaque nouvelle lecture d’un record, une nouvelle action est ajoutée.

La fonction CATX permet de concaténer les valeurs d’ACTION_LST et ACTION, et d’ajouter la barre comme délimiteur.

Voici donc le résultat intermédiaire, avant l’activation du code mis en commentaires.

pat_id  visit_dt action_lst

   1   02APR2007 RAYON X
   1   02APR2007 RAYON X | ULTRASON
   1   02APR2007 RAYON X | ULTRASON | SCANNER
   2   15NOV2007 ULTRASON
   2   15NOV2007 ULTRASON | RAYON X

A présent, il s’agit de garder seulement le dernier record de chaque visite par patient avec LAST.VISIT_DT et à supprimer les variables REC_ID et ACTION.

2. Rotation de données (PROC TRANSPOSE) et lecture en boucle (ARRAY)

Avec cette seconde approche, le travail est découpé en deux étapes à commencer.

Dans un premier temps, un PROC TRANSPOSE pour faire pivoter les données. Le data set n’a alors plus qu’une ligne par visite de patient. Chaque action apparaît dans une colonne donnée.

proc transpose data=orig out=final2 (drop=_name_);
   by pat_id visit_dt;
   var action;
run;

pat_id  visit_dt  COL1      COL2      COL3

   1   02APR2007  RAYON X   ULTRASON  SCANNER
   2   15NOV2007  ULTRASON  RAYON X

Dans un second temps un ARRAY nommé _ACTION est défini. Il contient toutes les variables commençant par COL. A chaque nouvelle lecture d’une variable COL, sa valeur est ajoutée à celle de la variable ACTION_LST.

data final2 (drop=i col:);
   set final2;
   length action_lst $200;
   array _action {*} col:;
   do i=1 to dim(_action);
      action_lst = catx(‘ | ‘,action_lst,_action{i});
   end;
run;

Annexe : Création du data set utilisé pour l’exemple.

data orig;
   input pat_id visit_dt date9. rec_id action $15.;
   format visit_dt date9.;
   datalines;
1 02APR2007 1 RAYON X
1 02APR2007 2 ULTRASON
1 02APR2007 3 SCANNER
2 15NOV2007 2 RAYON X
2 15NOV2007 1 ULTRASON
;
run;

proc sort data=orig;
   by pat_id visit_dt;
run;