Archive for the ‘Data Step’ Category

h1

Protégé : Avez-vous pensé à lire votre log de manière automatique

septembre 12, 2010

Cet article est protégé par un mot de passe. Pour le lire, veuillez saisir votre mot de passe ci-dessous :

h1

Protégé : Qui a la priorité : RETAIN ou SET ?

mars 30, 2010

Cet article est protégé par un mot de passe. Pour le lire, veuillez saisir votre mot de passe ci-dessous :

h1

Protégé : Newsletter Mars : solution

mars 1, 2010

Cet article est protégé par un mot de passe. Pour le lire, veuillez saisir votre mot de passe ci-dessous :

h1

Deux manières de créer un data set vide

juillet 2, 2009

Dans un précédent article Copier la structure d’un data set et se séparer des données, nous avons vu comment récupérer la structure d’une table (data set) de référence, c’est-à-dire copier les caractéristiques des variables sans les données. Ici, vous verrez comment créer un data set, appelé EMPTY, sans données et sans se baser sur un data set de référence.

L’intérêt est de souvent de pouvoir ensuite empiler des data sets ayant des longueurs de variables. En effet la longueur d’une variable rencontrée dans le premier data set sera la longueur de référence. Il ne faut pas qu’elle soit plus petite que celle du data set suivant. Autrement le texte des observations d’après est coupé (truncated).

1. Avec une étape data

Au choix, vous avez l’instruction ATTRIB ou les différentes instructions LABEL, LENGTH, FORMAT, INFORMAT pour créer les variables du data set.

data empty;
attrib var_text   label=‘Var. caractère, longueur 20’ length=$20
var_num_dt label=‘Var. numérique, longueur 8’ format=date9.;
stop;
run;

Dans la log, SAS précisera qu’aucune valeur n’a été donné aux variables VAR_TEXT et VAR_NUM_DT.

NOTE: Variable var_text is uninitialized.
NOTE: Variable var_num_dt is uninitialized.

2. Créer un data set vide avec la procédure SQL

La procédure SQL

proc sql;
create table empty
(
var_text char(20) label=‘Var. caractère, longueur 20’ ,
var_num_dt num label=‘Var. numérique, longueur 8’ format=date9.
);
quit;

3. Voir le résultat

J’ai choisi d’ajouter l’option VARNUM à la procédure PROC CONTENTS pour afficher les données dans l’ordre

proc contents data=empty varnum;
run;

La variable VAR_TEXT apparaît en premier. Il s’agit d’une variable alphanumérique de longueur 20 sans format et ayant pour libellé : Var. caractère, longueur 20.

La seconde variable VAR_NUM_DT est numérique, de longueur 8. Le format DATE9 est appliqué dessus de manière permanente. Le libellé de cette variable est : Var. numérique, longueur 8.

The CONTENTS Procedure

Variables in Creation Order

# Variable   Type   Len Format Label

1 var_text   Char   20         Var. caractère, longueur 20
2 var_num_dt Num     8  DATE9. Var. numérique, longueur 8

Lectures complémentaires

h1

Enlever les balises HTML d’un texte (do while et do until)

mai 18, 2009

Les balises HTML sont des mots entourés de < et > servant à la mise en forme de pages Internet. Dans l’exemple qui suit le but est d’enlever avec SAS des balises HTML contenues dans une variable appelée DESCRIP au moyen d’une boucle.  Cet exemple, basé sur un cas réel, permettra d’illustrer la syntaxe de DO UNTIL et de DO WHILE.

1. La fonction SUBSTR pour enlever un symbole <…>

Pour enlever une balise, je choisis ici de remplacer la chaîne commencant par < et se terminannat par > au moyen de la fonction SUBSTR. Pour ce faire,

  • paramètre 1 : donner le nom de la variable en premier
  • paramètre 2 : préciser la position du symbole < en second 
  • paramètre 3 : donner la longueur du texte en calculant le nombre de caractères entre ce symbole de début de balise et celui de fin (position de su symbole de fin > – position du symbole de début < + 1).

data no_tag (drop=tag:);
   descrip=‘<p>my text</p>’;
   tag_start = index(descrip,‘<‘);
   tag_end   = index(descrip,‘>’);
   substr(descrip,tag_start,tag_end-tag_start+1)=‘ ‘;
run;

Ici le texte à mettre à jour est <p>my text</p>. Cette première étape data remplace la première balise et seulement la première. Pour des raisons de lisibilité, j’ai choisi de créer deux variables intermédiaires qui retourne la position de < (variable TAG_START) et de > (TAG_END) au moyen de la fonction INDEX.

En fin d’étape data, toutes les variables dont le nom commence par TAG sont supprimée grâce à l’option DROP.

2. Répéter l’opération au moyen d’une boucle DO UNTIL

A chaque exécution de la boucle la variable DESCRIP est mise à jour : une balise <…> est enlevée.

La boucle sera exécutée jusqu’à ce qu’aucun symbole < ne soit identifié. En d’autres termes, la boucle sera exécutée jusqu’à ce que la fonction INDEX retourne la valeur zéro.

data no_tag (drop=tag:);
   descrip=‘<p>my text</p>’;
   do until(index(descrip,‘<‘)=0);
      tag_start = index(descrip,‘<‘);
      tag_end   = index(descrip,‘>’);
      substr(descrip,tag_start,tag_end-tag_start+1)=’ ‘;
   end;
run;

3. Répéter l’opération au moyen d’une boucle DO WHILE

A chaque exécution de la boucle la variable DESCRIP est mise à jour : une balise <…> est enlevée.

La boucle sera exécutée tant qu’un symbole < sera identifié. En d’autres termes, la boucle sera exécutée tant que la fonction INDEX ne retournera pas la valeur zéro.

data no_tag (drop=tag:);
   descrip=‘<p>my text</p>’;
   do while(index(descrip,‘<‘) ne 0);
      tag_start = index(descrip,‘<‘);
      tag_end = index(descrip,‘>’);
      substr(descrip,tag_start,tag_end-tag_start+1)=‘ ‘;
   end;
run;

Avec DO UNTIL et DO WHILE, il faut faire attention aux boucles infinies. Si la condition pour sortir de la boucle n’est jamais obtenue. L’exécution continue sans fin.

Lectures complémentaires

Sur le blog www.sasreference.fr

Online Doc

  • DO WHILE Statement
  • DO UNTIL Statement
h1

Un premier exemple d’array : changer toutes les variables 1/2 en variable 0/1

mai 11, 2009

Imaginez que vous avez dans une table des variables oui/non où 1 représente non et 2 représente oui. Changement de standard oblige, vous devez symboliser les non par un 0 et les oui par un 1.

Si mavariable=1 alors mavariable=0.
Sinon mavariable=1.

Bien sûr, vous pouvez traiter séparément chaque variable. Ce chantier laborieux est remplaçable par une boucle où seul le nom de la variable change à chaque fois. Vous voulez donc effectuer une même opération sur un grand nombre de variables. La syntaxe de l’array est faite pour vous.

1. Un data set pour l’exemple

Voici la table (SAS data set) utilisée pour l’exemple. Elle s’appelle FINAL. Elle est composée d’une variable caractère et de trois variables numériques, toutes des variables binaires de type oui (2)/ non (1).

data final;
input subject $ pregny validny aeny;
datalines;
A 1 2 1
B 1 1 2
C 2 1 2
D 1 2 2
;
run;

Le but sera d’obtenir un data set avec des variables binaires de type oui (1)/ non (0).

subject pregny validny aeny;
A      0       1      0
B      0       0      1
C      1       0      1
D      0       1      1

2. C’est quoi un array ?

Un array est un nom qui désigne une liste de variables. Il est propre à l’étape data.

  • Définir un nouvel array : Dans un premier temps, l’array est à créer: Sous un nom de son choix, sont sauvegardés sauvegarde des noms de variables (les éléments de l’array) dont l’ordre est indexé pour pouvoir les désigner de manière individuelle par la suite.
  • Appler les variables contenues dans l’array : Dans un second temps, chaque élément de l’array (chaque variable) est appelé/désigné, non pas par son nom, mais par sa position dans l’array.

3. Définir un array

Pour définir un array, il existe l’instruction ARRAY. Elle est composée de trois parties principales et d’un quatrième optionnel.

  • le nom de l’array
  • le nombre de variables  listées (le nombre d’éléments dans l’array)
  • le nom des variables
  • la valeur des variables (optionel)

Dans l’exemple, j’ai un array nommé NY composé de trois éléments : les variables PREGNY (prenant no/yes), VALIDNY (valid no/yes) et AENY (adverse event no/yes).

data final;
set final;
*array ny {1998:2000} pregny validny aeny;
*array ny {1:3} pregny validny aeny;
array ny {*} pregny validny aeny;
run;

Je vous propose trois alternatives pour la notation. Ma préférence, pour des raisons de simplicité dans ce cas, va au cas numéro trois.

  • {1998:2000} Dans le premier cas, la variable PREGNY a pour référence la position 1998, VALIDNY a pour référence la position 1999 et la variable AENY est en position 2000.
  • {1:3} Dans le second cas, la numérotation commence à 1 avec la variable PREGNY et se termine à 3 avec la variable AENY.
  • {*} Dans le troisième et dernier cas, la numérotation est implicite. Comme précédemment. Elle ira de 1 à 3. SAS se charge de compter le nombre de variables pour savoir la dimension de l’array. Si SAS fait le travail pour nous, pourquoi se priver de ce luxe !

Note : La première syntaxe peut apporter dans certains cas un plus en terme de compréhension. C’est le cas quand le numéro a un lien avec le sens de la variable. Par exemple, les variables RESULT98, RESULT99 et RESULT00 peuvent avoir les positions 1998, 1999 et 2000 et donc avoir un caractère informatif.

4. Appeler un array

Pour appeler un élément d’un array (une variable), il faut donner le nom de l’array suivi de la position de la variable dans l’array. Ainsi :

  • ny{1} désigne la variable PREGNY
  • ny{2} fait référence à la variable VALIDNY
  • ny{3} concerne la variable AENY

data final;
set final;
array ny {*} pregny validny aeny;
*variable PREGNY;
if ny{1}=1 then ny{1}=0;
else ny{1}=1;
*variable VALIDNY;
if ny{2}=1 then ny{2}=0;
else ny{2}=1;

*variable AENY;
if ny{3}=1 then ny{3}=0;
else ny{3}=1;

run;

L’intérêt de cette notation vient dans l’usage d’une boucle où la position de la variable sera automatiquement changé.

data final;
set final;
array ny {*} pregny validny aeny;
do i=1 to dim(ny)
;*do i=1 to 3;
if ny{i}=1 then ny{i}=0;
else ny{i}=1;
end;
run;

Pour les plus paresseux comme moi, on demandera à SAS de calculer le nombre d’éléments contenus dans l’array (la dimension) au moyen de la fonction SAS propre à l’array DIM().

Je vous proposerai dans les semaines à venir un autre article sur les subtilités de l’array.

h1

Tout sur l’instruction BY

avril 14, 2009

Me rendant compte que l’instruction BY pouvait poser des difficultés lorsqu’on débute avec SAS, j’ai décidé de faire le point sur cette instruction.

1. Une instruction locale

L’instruction BY peut servir dans toutes les étapes data et procédures à l’exception de PROC SQL.

2. Un ordre défini par le nom des variables :

L’instruction BY est suivie du nom des variables servant pour le tri.

Dans un premier temps, les observations sont triées selon les valeurs de la première variable citée, ici SEX. Puis, pour chacune des valeurs prises par SEX (M et F), les données sont triées par NAME.

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

3. PROC SORT : le premier usage de l’instruction BY : L’instruction BY est logiquement obligatoire dans un PROC SORT. Sinon SAS ne saurait pas dans quel ordre trier les données. Le mot DESCENDING peut-être ajouté pour préciser un ordre décroissant. Ici les données sont d’abord triées par SEX puis par nom en ordre descendant.

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

L’autre manière de trier les données est d’utiliser la procédure PROC SQL.

Idée : Vous aurez souvent un PROC SORT avant d’utiliser l’instruction BY dans une autre procédure ou étape data. Simplifiez-vous la vie en copiant l’insstruction au niveau du PROC SORT et en la collant au niveau de la procédure ou étape data suivante.

4. SAS vous informe si les données ne sont pas triées comme indiqué

L’instruction BY précise à SAS dans quel ordre les données doivent être lues. Si les données ne respectent pas cet ordre, SAS s’arrête et fourni un message d’erreur.

5. L’instruction BY : obligatoire ou optionnelle ?

L’instruction BY est optionelle dans une instruction SET. Utilisée pour empiler les données de deux data sets, elle permettra d’intercaler les observations des deux sources selon leur valeurs au lieu de mettre d’abord toutes les observations du premier data set cité et ensuite toutes les observations du second data set.

L’instruction BY reste pratiquement indispensable avec MERGE puisqu’elle sert à relier les observations de deux data sets par les variables du même nom. Sans elle, les observations du second data set pour les variables du même nom réécrirait sur celle du premier.

L’instruction BY est indispensable avec FIRST et LAST.

6. D’autres usages de l’instruction BY

L’instruction BY peut s’ajouter dans un PROC REPORT. Une option NOBYLINE permettra de changer le titre à chaque nouvelle combinaison de valeurs désignée par l’instruction. Néanmoins la mise à jour du titre par cette approche avec ODS RTF par exemple ne fonctionne pas.

L’instruction BY peut servir dans toutes less procédures (sauf PROC SQL) et notamment dans les procédures statistiques. Voir dans les lectures complémentaire l’usage de l’instruction BY avec PROC FREQ.

Lectures Complémentaires

SAS Online Doc

  • BY-Group Processing in SAS Programs
h1

Les anniversaires, cela se fête avec SAS

avril 2, 2009

Aujourd’hui étant mon anniversaire, je fais la paresseuse et vous communique un petit fichier SAS, reçu ce jour (merci Alex), à faire tourner sous Windows, écouteurs en place, pour la prochaine fois qu’un collègue ou pote qui connaît SAS soufflera ses bougies. Amusez-vous bien !

%let pc=1;

%macro sasreference_fr(note,octave,length);

select(&note.);
when (‘A’) call sound (55*(2**&octave.),&length.*160*&pc.);
when (‘A#’) call sound (58*(2**&octave.),&length.*160*&pc.);
when (‘Bb’) call sound (58*(2**&octave.),&length.*160*&pc.);
when (‘B’) call sound (62*(2**&octave.),&length.*160*&pc.);
when (‘C’) call sound (65*(2**&octave.),&length.*160*&pc.);
when (‘C#’) call sound (69*(2**&octave.),&length.*160*&pc.);
when (‘Db’) call sound (69*(2**&octave.),&length.*160*&pc.);
when (‘D’) call sound (73.5*(2**&octave.),&length.*160*&pc.);
when (‘D#’) call sound (73.5*(2**&octave.),&length.*160*&pc.);
when (‘Eb’) call sound (78*(2**&octave.),&length.*160*&pc.);
when (‘E’) call sound (82*(2**&octave.),&length.*160*&pc.);
when (‘F’) call sound (87*(2**&octave.),&length.*160*&pc.);
when (‘F#’) call sound (92.5*(2**&octave.),&length.*160*&pc.);
when (‘Gb’) call sound (92.5*(2**&octave.),&length.*160*&pc.);
when (‘G’) call sound (98*(2**&octave.),&length.*160*&pc.);
when (‘G#’) call sound (104*(2**&octave.),&length.*160*&pc.);
when (‘Ab’) call sound (104*(2**&octave.),&length.*160*&pc.);
when (‘R’) call sleep((&length./3)*&pc.,1);
otherwise;
end;
%mend sasreference_fr;

data _null_;
%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘D’,3,2);
%sasreference_fr(‘C’,3,2);
%sasreference_fr(‘F’,3,2);
%sasreference_fr(‘E’,3,4);

%sasreference_fr(‘R’,3,2);

%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘D’,3,2);
%sasreference_fr(‘C’,3,2);
%sasreference_fr(‘G’,3,2);
%sasreference_fr(‘F’,3,4);

%sasreference_fr(‘R’,3,2);

%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘C’,3,1);
%sasreference_fr(‘C’,4,2);
%sasreference_fr(‘A’,4,2);
%sasreference_fr(‘F’,3,1);
%sasreference_fr(‘F’,3,1);
%sasreference_fr(‘E’,3,2);
%sasreference_fr(‘D’,3,4);

%sasreference_fr(‘R’,3,2);

%sasreference_fr(‘Bb’,4,1);
%sasreference_fr(‘Bb’,4,1);
%sasreference_fr(‘A’,4,2);
%sasreference_fr(‘F’,3,2);
%sasreference_fr(‘G’,3,2);
%sasreference_fr(‘F’,3,4);
run;

Pour les curieux, je vous invite à consulter les programmes des chansons suivantes suggérées sur le forum de developpez.com :

Les plus téméraires s’intéresserons à la publication « Making Music in SAS« . Vos créations pourront être publiées sur le blog.

A lire aussi www.sasreference.fr :

h1

Modifier un data set sans le lire (formater, renommer, libeller)

mars 5, 2009

Sous SAS, il est possible d’ajouter et supprimer des formats avec une étape data. Cela implique la lecture des données. Pour s’attaquer aux formats sans lire les données, il y a la procédure PROC DATASETS. Quelle est la syntaxe à soumettre ? Quelles sont les autres modifications possibles ? Tout d’abord, vous trouverez le data set servant d’exemple. Puis, la version classique avec l’étape data est présentée suivie de la syntaxe de PROC DATASETS.

1. Les données servant d’exemple, le data set CLASS

Un data set CLASS : Dans cet exemple, un data set CLASS est créé dans la bibliothèque WORK. Il se base sur le data set du même nom situé dans la bibliothèque SASHELP.

Une variable SEX avec un format : Dans ce data set, on trouve une variable nommée SEX. Un format est appliqué sur cette variable de manière permanente (jusqu’à qu’il soit explicitement supprimé ou jusqu’à ce que le data set soit supprimé).

Un format SEX : Le format est également appelé SEX. Il est créé au préalable dans une procédure PROC FORMAT. Les valeurs ‘M’ apparaissent alors sous la forme ‘Male’ (homme) et les ‘F’ apparaissent sous la forme ‘Female’ (femme).

*create a format called SEX;
proc format;
   value $ sex 'M'='Male'
               'F'='Female';
run;
*Create a data set named CLASS ;
*based on the SASHELP.CLASS data set ;
*adding the SEX format to the SEX variable;
data class;
   set sashelp.class;
   format sex sex.;
run;

2. Solution avec une étape data

Nom du data set final : Dans cette étape data (data step), une table SAS (SAS data set) CLASS1 est créée à partir du data set CLASS.

Un label pour le data set : Un libellé (label) est appliqué sur le data set afin d’enrichir la compréhension globale du nouveau data set. Le libellé est « Changes with a Data Step ».

Renommer une variable : la variable WEIGHT (poids) est renommée. Elle s’appelle à la fin WEIGHT_STONE (poids en stone).

Un label pour une variable : un libellé est ajouté à la variable NAME du data set pour faciliter de nouveau la compréhension, de la variable cette fois. Le libellé est « Student Name ».

Traîter les formats : Enfin, l’instruction FORMAT enlève, dans le cas présent, le format de toutes les variables. Si vous voulez enlever seulement le format associé à la variable SEX, utilisez l’instruction en commentaire. Vous pouvez aussi assigner des formats sur d’autres variables avec une instruction FORMAT.

data class1;
   set class (label='Changes with a Data Step' rename=(weight=weight_stone));
   label name='Student Name';
   format _all_;
   *format sex;
 run;

*View the data step result;
proc print data=class1 label;
run;


3. Solution avec la procédure PROC DATASETS

Nom du data set final, instruction CHANGE : A la différence de l’étape data, ici aucun nouveau data set n’est créé. Le data set d’origine est renommé. En d’autres termes, le data set CLASS n’existe plus en tant que tel. L’instruction CHANGE a servi à faire la manipulation.

Un label pour le data set, instruction MODIFY : Un libellé (label) est appliqué sur le data set au moyen de l’instruction MODIFY. Le libellé est « Changes with PROC DATASETS ».

Renommer une variable, instruction RENAME (+MODIFY) : la variable WEIGHT est renommée WEIGHT_STONE au moyen de l’instruction RENAME après avoir utlisé l’instruction MODIFY.

Un label pour une variable, instruction LABEL (+MODIFY) : l’instruction LABEL utlisée en combinaison avec MODIFY ajouter le libellé « Student Name » à la variable NAME.

Traîter les formats, instruction FORMAT (+MODIFY) : Enfin, l’instruction FORMAT enlève, dans le cas présent, le format de toutes les variables.

proc datasets;
   change class=class2;
   modify class2 (label='Changes with PROC DATASETS');
   rename weight=weight_stone;
   label name='Student Name';
   format _all_;
run;
*View the PROC DATASETS result;
proc print data=class1 label;
run;
h1

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

février 16, 2009

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

Lectures complémentaires :

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

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

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

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

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

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

patref ae_id

   2     1
   4     1
   4     2

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

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

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

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

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

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

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

proc format cntlin=pat;
run;

3. Sélectionner les observations de son choix

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

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

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

Voir le résultat :

proc print data=ae_multi;
run;
h1

Deux méthodes pour sélectionner des données en se basant sur un second data set

janvier 26, 2009

Avec IF/SELECT/WHERE, OUTPUT/DELETE vous savez comment garder une partie des données disponible en fonction de la valeur de variables. Mais comment faire si les données servant de critère sont dans un autre data set ?

Voici un exemple :

  • D’un côté, on a un data set SAS avec tous les effets secondaires (adverse events)  de tous les patients. Un patient peut avoir plusieurs effets secondaires et donc plusieurs lignes. Il peut aussi ne pas être présent s’il aucun effect secondaire n’a été enregistré.
  • De l’autre côté on a un data set contenant seulement les patients répondant aux critères du protocol d’étude clinique (une ligne par patient).

Comment garder tous les effects secondaires de ces patients valides par protocole et seulement de ceux-là ?. SAS a deux possibilités :

  1. un MERGE dans une étape data utilisé avec son option (IN=)
  2. un PROC SQL avec la condition WHERE… IN ().

Vous trouverez un rappel sur le MERGE en lisant : « La base de la jointure de deux data sets avec MERGE« .

1. Les data sets AE_MULTI et PAT_UNIQ servent d’exemple

Une ou plusieurs lignes par patients dans le data set AE_MULTI : le data set AE_MULTI contient six effets secondaires (6 lignes d’observations) se référant à 4 patients (numéros : 1, 2, 4 et 5).

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

Une seule ligne par patient dans le data set PAT_UNIQ : le data set PAT_UNIQ contient trois patients (3 observations) : numéros 2, 3 et 4.

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

En d’autres termes, on souhaite garder les observations de AE_MULTI si et seulement si le patient est aussi enregistré dans le data set PAT_UNIQ. Trois observations sont à conserver : celles du patient 2 avec ses deux effets secondaires et celle du patient 4 avec son effet secondaire.

patref    ae_id

   2        1
   4        1
   4        2

2. Deux solutions

Dans ce cas du MERGE, on annote (flag) les données avec des variables temporaires (AE et PAT).

  • Si la valeur de PATREF est présente dans le fichier AE_MULTI, alors AE=1, sinon AE=0.
  • Si la valeur de PATREF est présente dans le fichier PAT_UNIQ, la variable PAT=1, sinon elle est égale à 0.

Si le patient est à la fois dans les deux data sets  (si AE=1 et PAT=1), alors les données sont envoyées (ouputted) dans le data set VERSION1.

Comme se sont les variables du data set AE_MULTI qui nous intéresse et non celles du data set PAT_UNIQ, on ne garde parmi les variables de PAT_UNIQ seulement la variable PATREF servant de lien et listée dans l’instruction BY.

data version1;
   merge ae_multi (in=ae)
         pat_uniq (in=pat keep=patref);
   by patref;
   if ae and pat;
run;

Avec la procédure SQL, on sélectionne toutes les données disponibles dans le data set AE_MULTI en précisant que les valeurs de la variable PATREF doit aussi être présentes dans une autre sélection, celle définie entre parenthèses.

proc sql;
   create table version2 as
      select *
      from ae_multi
      where patref in (select patref from pat_uniq);
quit;

Entre les deux méthodes, on notera deux différences :

  1. Avec le merge, il est possible de lier des data sets ayant plus d’une variable commune (by pays centre patient;).
  2. Avec la procédure SQL, on peut multiplier les données dans le WHERE. Par exemple, on pourrait à la fois choisir les patients qui sont dans le data set PAT_UNIQ et exclure les effets secondaires qui sont aussi présents dans un autre fichier que AE.
h1

Deux réponses possibles avec la fonction IFN

janvier 19, 2009

Les fonctions IFN et IFC existent depuis la version 9.1 de SAS. Elles permettent de retourner une valeur si une condition est remplie et une autre si ce n’est pas le cas. Je vous propose d’illustrer la fonction IFN en combinaison avec la fonction LAG.

1. La différence entre les fonctions IFN et IFC

La fonction IFN retourne une valeur numérique alors que la fonction IFC retourne une valeur caractère.

2. Trois paramètres obligatoires pour ces fonctions et un optionnel

Dans un premier temps, il s’agit de définir une condition.

  • Paramètre 1 : définir la condition

Dans un second temps, on assigne chacune des valeurs prises par la nouvelle variable selon que

  • Paramètre 2 : valeur si la condition est remplit,
  • Paramètre 3 : valeur si la condition n’est pas remplit
  • Paramètre 4 : valeur si la condition donne une valeur manquante (optionnel).

3. L’exemple

Dans cet exemple, on a trois variables : PATIENT_ID et CNTRY_ID sont les variables clés. STRT_DT est la date de début d’un effet secondaire.

data adverse_events;
   input patient_id cntry_id $ strt_dt;
   informat strt_dt date9.;
   datalines;
999 DE 03MAR2004
999 DE 04MAR2004
999 DE 06MAR2004
111 AU 12DEC2003
111 AU 15DEC2003
;
run;

On souhaite créer une nouvelle variable contenant la date précédente par patient.

patient_id cntry_id  strt_dt    prev_dt

    999       DE    03MAR2004       .
    999       DE    04MAR2004   03MAR2004
    999       DE    06MAR2004   04MAR2004
    111       AU    12DEC2003       .
    111       AU    15DEC2003   12DEC2004

La solution classique serait d’utiliser un FIRST qui implique que les données soient triées au préalable par patient.

proc sort data=adverse_events;
   by patient_id cntry_id;
run;

data adverse_events;
   set adverse_events;
   by patient_id cntry_id;
   prev_dt=lag(strt_dt);
   first.cntry_id then prev_dt=.;
run;

Mais maintenant qu’on a la fonction IFN, la démarche est plus rapide. Dans notre exemple, seuls les trois paramètres obligatoires de la fonction IFN sont utilisés.

data adverse_events;
   set adverse_events;
   prev_dt=ifn(patient_id=lag(patient_id) and cntry_id=lag(cntry_id),
               lag(strt_dt),
               .);
run;

4. Liens

La fonction LAG

h1

5 points à retenir sur l’opérateur logique LIKE

décembre 14, 2008

Comment dire à SAS de sélectionner toutes les observations pour lesquelles une variable donnée contient le mot CASTS ? L’opérateur logique LIKE, utilisable uniquement une condition exprimée par WHERE est fait pour ce travail. Voici donc 5 points à retenir sur LIKE que vous pourrez vous même vérifier à l’aide du data set founi en bas d’article dans la rubrique « Annexe » et des exemples de la section 2.

1. Les 5 points à retenir sur LIKE

1. Trouver un texte ayant une structure donnée : Le but de LIKE est de trouver, pour une variable donnée, toutes les observations ayant une structure particulière.

2. Traiter des chaînes de caractères : LIKE s’applique à une chaîne de caractères et non à des valeurs numériques.

3. Autoriser un caractère libre : Le tiret bas (underscore : _) désigne qu’il faut absolutement un caractère à l’endroit où il est utilisé : ni plus ni moins.

4. Autoriser une chaîne de caractère libre : Le pourcentage (percent : %) accepte toute chaîne de caractère, quelque soit sa longueur, à l’endroit où le symbole apparaît. L’absence de caractère est aussi valide.

5. Appliquer LIKE dans un WHERE : LIKE s’utilise uniquement avec WHERE dans une étape data ou dans la procédure SQL. Il ne fonctionnera pas avec IF.

2. Quelques exemples

Un exemple avec les pourcentages : Dans ce premier exemple, on sélectionne toutes les lignes d’observations où la variable TEST_LAB contient le mot CASTS en majuscule. Il est possible de prendre une observation contenant du texte ou des blancs avant le mot CASTS et/ou après le mot CASTS.

data casts;
   set lab (where=(test_lab like '%CASTS%'));
run;

Pour prendre toutes les observations indépendamment de la case ajouter la fonction UPCASE autour du nom de la variable UPCASE(TEST_LAB) like…

Un exemple avec le tiret bas : imaginons que vous vouliez repérer toutes les tests en rapport avec « Leukocyte esterase » mais vous envisagerez une mauvaise saisie au niveau du k, c et y. Vous demandez alors toutes les observations ressemblant au mot « Leukocyte esterase » en acceptant n’importe quelle autre valeur pour k, c et y.

data check_leuk;
   set lab (where=(test_lab like 'LEU_O__TE ESTERAS'));
run;

Un exemple combinant pourcentage et tiret bas : dans ce troisième et dernier exemple, on cherche à trouver toutes les observations contenant le mot CAST tout en assumant que la lettre A peut être erronnée dans les données du data set LAB. N’importe quel caractère à l’emplacement du A est autorisé.

data check_casts;
   set lab (where=(test_lab like '%C_ST%'));
run;

La même chose avec PROC SQL

proc sql;
   create table check_casts as
       select *
       from lab
       where test_lab like '%C_ST%';
quit;

Annexe : CASTS réfère à des tests de laboratoires sur les urines (urinal test).

data lab;
   length test_label $100;
   input test_label $;
   datalines;
FATTY CASTS
GRANULAR CASTS
HYALINE CASTS
RED BLOOD CELL COSTS
LEUKOCYTE ESTERASE
RENAL TUBULAR EPITHELIAL CASTS
WAXY CASTS
WHISTE BLOOD CELL CASTS
KETONE
;
run;
h1

Créer un fichier .sas automatiquement

décembre 4, 2008

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

1. Le data set pour l’exemple

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

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

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

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

Ou

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

Ou

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

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

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

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

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

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

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

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

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

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

4. Une étape data

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

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

5. Exécuter le programme

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

Appeler le programme :

%include sasref;

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

filename sasref clear;

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

h1

Lire des données d’un fichier .TXT sans perdre d’information (les options d’INFILE)

novembre 7, 2008

L’accès à des données contenues dans un fichier externe du type .TXT se fait sous SAS par l’intermédiaire d’une étape data et de l’instruction INFILE. Plusieurs options sont possibles pour cette instruction. Il est important de connaître les forces et faiblesses de chacune afin de faire le bon choix. Cet article vous présentera dans un premier temps le fichier .TXT qui servira d’exemple. En premier lieu, il sera appelé avec l’option FLOWOVER, l’option par défaut. Puis, cela sera le tour des options TRUNCOVER et MISSOVER/PAD.

1. Aperçu sur les données contenu dans le fichier .TXT

Afin de montrer les nuances entre les options FLOWOVER, TRUNCOVER et MISSOVER, un fichier EG_INFILE.TXT est créé. Ce fichier contient les données pour deux variables caractères CNTRY (country) et CNT (count).

Dans l’aperçu qui suit, j’ai remplacé les espaces par des points afin de vous puissiez visualiser la différence que peuvent créer certains espaces.

  • La première ligne contient 2 caractères
  • Les seconde et troisième lignes contiennent 12 caractères
  • L’avant dernière ligne n’en contient que 4
  • La dernière en contient 12 si on inclus les espaces de fin.

Note : « e.g. » est la version raccourcie de « example » en anglais. C’est donc notre équivalent de « ex ».

IT
CA.12.......
BE.123456789
KR.
MY.2
FI.1........

Le choix du FILENAME : Par choix, je crée un mot SASREF qui désigne le chemin d’accès au fichier EG_INFILE.TXT. Cela évitera d’avoir à recopier le chemin dans chaque étape data. Toute mise à jour ou correction du chemin d’accès se fera en une seule fois évitant tout oubli.

filename sasref 'C:/sasref/eg_infile.txt';

Note : Il est important de définir une longueur pour les variables caractères. Sinon les variables ayant plus de 8 caractères sont tronquées. Dans notre cas, la valeur 123456789 deviendrait 12345678.

2. FLOWOVER, l’option par défaut

Par défaut, SAS applique l’option FLOWOVER avec une instruction INFILE. Ainsi l’instruction INFILE mise en commentaire, en ajoutant une étoile en tête d’instruction, donnerait le même résultat que celle active.

data eg_flowover;
   infile sasref;
   *infile sasref flowover;
   length cntry $2 cnt $9;
   input cntry $ cnt $;
run;

L’aperçu qui suit montre très clairement que SAS continu sa lecture sur la ligne suivante s’il n’a pas trouvé une valeur pour chaque variable dans la ligne actuelle.

  • Créer la première ligne d’observations : En ligne 1, il manque une valeur pour CNT. SAS va en ligne deux et récupère la première valeur. Il ignorera toutes les valeurs qui peuvent exister sur le reste de la ligne. Il lui a donc fallu deux lignes en entrée pour créer une ligne en sortie.
  • Créer la seconde ligne d’observations : après avoir lu les deux premières lignes, SAS passe à la troisième ligne pour créer la seconde ligne d’observations. Il trouve son bonheur ici puisqu’il y a une valeur par variable.
  • Créer la troisième ligne d’observations : à la ligne suivante, il manque de nouveau une valeur. SAS assigne la valeur KR à la variable CNTRY. Mais ne trouvant pas de valeur pour la variable CNT, il passe à la ligne suivante et trouve la valeur MY.
  • Créer la quatrième et dernière ligne d’observations : il ne reste a SAS plus qu’une ligne de disponible dans le fichier d’entrée. Cette ligne contient une observation par variable. SAS est content avec.
cntry  cnt

  IT   CA
  BE   123456789
  KR   MY
  FI   1

3. L’option TRUNCOVER empêche le passage à la ligne et ne se formalise pas des longueurs

L’option TRUNCOVER palie à ce problème en empêchant à SAS d’aller voir à la ligne suivante

data eg_truncover;
   infile sasref truncover;
   length cntry $2 cnt $9;
   input cntry $ cnt $;
run;

Le résultat est comme escompté : 

cntry   cnt
  IT
  CA    12
  BE    123456789
  KR
  MY    2
  FI    1

4. L’option MISSOVER empêche le passage à la ligne

Les limites de l’option MISSOVER avec un INFILE : L’option MISSOVER est une autre option possible de l’instruction INFILE. Elle présente néanmoins une limite due à des espaces.

data eg_missover;
   infile sasref missover;
   length cntry $2 cnt $9;
   input cntry $ cnt $;
run;

Dans l’exemple, la valeur de CNT (2) quand CNTRY=MY disparaît, alors quela valeur de CNT (1) quand CNTRY=FI reste. Alors que la Qu’est ce qui a provoqué cela ?

Vous souvenez vous de la remarque concernant les espaces en fin de ligne dans la première section de cette article. SAS recherche 9 caractères pour créer une valeur pour CNT. Hors quand CNTRY=MY, il n’en trouve qu’un. Cela ne le satisfait pas. Comme, avec MISSOVER, il ne peut pas aller voir sur la ligne d’après. Il se contente de mettre une valeur manquante.

cntry   cnt

  IT   
  CA    12
  BE    123
  KR   
  MY   
  FI    1

L’équivalent de TRUNCOVER : L’option MISSOVER en combinaison avec l’option PAD fournira le même résulat que l’option TRUNCOVER. Autant donc utiliser un seul mot en la personne de TRUNCOVER.

data eg_missover_pad;
   infile sasref missover pad;
   length cntry $2 cnt $9;
   input cntry $ cnt $;
run;

Le cas particulier du DATALINES : MISSOVER avec un DATALINES ne rencontre pas le problème des blancs de fin de ligne manquants.

data eg_missover;
   infile datalines missover;
   length cntry $2 cnt $9;
   input cntry $ cnt $;
   datalines;
IT
CA 12
BE 123456789
KR
MY 2
FI 1
;
run;

Conclusion

Nous avons vu un cas particulier de l’instruction INFILE : lecture d’un fichier dans lequel chaque ligne est sensée représenter une ligne d’observations.

Par défaut, SAS recherche autant d’emplacements (texte ou espaces) dans le fichier qu’il lit que celui donné par la longueur d’une variable. Faute de quoi SAS jetera un coup d’oeil à la ligne suivante (FLOWOVER) ou ignorera certaines valeurs (MISSOVER) selon l’option indiquée dans l’instruction INFILE.

L’option TRUNCOVER répond aux deux problèmes (passage à la ligne et manque de place sur une ligne). Il est donc judicieux de privilégier l’option TRUNCOVER sur MISSOVER pour ce problème précis.

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

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

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;