Archive for the ‘Base’ Category

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

Remplacer un mot par un autre : la fonction TRANWRD

février 10, 2009

La fonction TRANWRD (entendez par là Translate Word) de SAS sert à remplacer un mot par un autre. Quelle est la syntaxe de base ? Quelles sont ses particularités ? A quoi faut-il faire attention lorsqu’on l’utilise ?

1. Le test

data one;
  x='AbcDeffeDGhiDefDEF';
  y1=tranwrd(x,'Def','ZZ');
  length y2 $18;
  y2=tranwrd(x,'Def','ZZZZ');
run;

Voir le data set ONE :

         x                    y1                   y2

AbcDeffeDGhiDefDEF    AbcZZfeDGhiZZDEF    AbcZZZZfeDGhiZZZZD

2. La syntaxe de base

La fonction TRANWRD est composée de 3 paramètres :

  • Le texte d’origine : une variable caractère ou une chaîne de caractères entre guillemets.
  • Le texte à remplacer
  • Le nouveau texte

Note : Les paramètres caractères d’origine et nouveau texte sont inversés dans la fonction TRANSLATE.

3. Les particularités de la fonction TRANWRD

Remplacer un mot : dans l’exemple, ce ne sont par les lettres D, e et f qui sont remplacées mais bien le mot ‘Def’. C’est pour cela que le texte ‘feD’ reste intacte.

Sensible à la case : dans l’exemple, le texte ‘DEF’ n’est pas remplacé car ‘E’ et ‘F’ sont en majuscule. Seul le texte ‘Def’ est changé.

Un nouveau mot de longueur différente : dans l’exemple,

  • Un texte plus court : la variable Y1 voit le mot ‘Def’ composé de trois lettres remplacé par le mot plus court ‘ZZ’ sans blanc à la suite
  • Un texte plus long : le mot ‘Def’ remplacé par un mot plus long ‘ZZZZ’ et donne la variable Y2. Le texte qui suit est tout simplement décalé pour donner la place nécessaire.

4. Redéfinir les longueurs si nécessaire 

Si votre nouveau texte est plus long que votre ancien texte, il est important de vérifier que la longueur de la variable est suffisant epour que l’intégralité de la chaîne de caractères soit conservée. Ici, la variable Y2 a une longueur de 18. Il manque la place à un caractère. Le F de fin est tronqué.

En savoir plus : TRANWRD function (SAS Online Doc)

Un exemple d’utilisation de la fonction TRANWRD : « Afficher 7h30 sous la forme 07:30« .

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

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

novembre 24, 2008

Ce dernier article de notre série sur le calcul d’un total par variable (contrat) sous SAS aborde la procédure PROC TABULATE. Comme précédemment, les résultats sont redirigés vers un data set.

1. Rappel

La source de la thématique : Cette série d’articles est basée sur une question posée sur le forum de www.commentcamarche.net : vous pouvez retrouver la question d’origine sur leur site.

Les autres articles : Vous pouvez retrouver les précédents articles de la série ici :

Les données :Les données sont sauvegardées dans un data set nommé CONTRATS. Il contient 4 variables :

  • l’identifiant de chaque client CLIENT,
  • le nombre de contrats NB_CNTR et
  • deux variables binaires TEL et HABITAT indiquant si oui ou non les fréquences s’appliquent.

Au total, on compte 9 contrats téléphoniques et 5 contrats d’habitation.

Créer le data set CONTRATS

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;

2. La réponse de PROC TABULATE

Lister les variables dans l’instruction VAR : Dans un premier temps les variables binaires TEL et HABITAT sont listées. Là encore il faut préciser le poids de chaque valeur. L’option WEIGHT introduit la variable NB_CONTR, notre coefficient multiplicateur.

Exprimer le calcul requis dans l’instruction TABLE : Pour chacune des variables TEL et HABITAT, la somme est faite en tenant compte du coefficient. Les résultats sont des nombres entiers mais SAS ajoute par défaut des chiffres après la virgule (des zéros donc ici). Pour s’en débarasser, un format 5. est appliqué aux sommes. La sonne ne devra donc pas être un nombre avec plus de 5 chiffres.

Empêcher l’affichage dans la fenêtre OUTPUT : La sortie générée par PROC TABULATE s’appelle TABLE. Par défaut, le résultat est envoyé dans la fenêtre OUTPUT. Pour empêcher cette redirection le temps du PROC TABULATE, les options ODS EXCLUDE doivent être activées.

Rediriger ses résultats dans un data set avec l’ODS (Output Delivery System) : Le data set contenant les résultats s’appelle SOLUTION5. Il est créé avec l’instruction ODS OUTPUT.

*ods exclude table;
proc tabulate data=contrats;*out=solution5;
   var tel habitat / weight=nb_cntr;
   table tel habitat, (sum='Frequency')*f=5.;
   ods output table=solution5;
run;
*ods exclude none;

L’ancienne méthode pour créer un data set, l’option OUT= : L’ancienne méthodeconsiste à ajouter l’option OUT= dans l’instruction PROC TABULATE. Mais cette syntaxe n’est pas généralisable à toutes les procédures et est donc plus difficile à se souvenir pour des utilisations occasionnelles.

3. Améliorer le fichier de sortie

Un simple PROC PRINT sur le fichier SOLUTION5 montre que

_TYPE_ _PAGE_ _TABLE_ tel_Sum habitat_Sum

   0      1      1        9       5

Pour changer l’orientation des résultats, vous pouvez faire appel à un PROC TRANSPOSE.

proc transpose data=solution5 out=solution5 (drop=_LABEL_);
   var tel_sum habitat_sum;
run;

Reste à vous d’améliorer la présentation avec des RENAME, LABEL appropriés, etc.

  _NAME_     COL1
tel_Sum       9
habitat_Sum   5
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;