h1

6 conseils pour vos emails

juillet 7, 2008

Le programmeur SAS ne fait pas exception dans le monde du travail lorsqu’il s’agit de communiquer par email avec ses partenaires et collaborateurs.

Dans l’industrie pharmaceutique, le programmeur travaillera souvent à distance avec un statisticien qu’il n’aura parfois jamais vu. Ensemble, ils clarifieront les caractéristiques d’un tableau à fournir et compareront leurs résultats. Le programmeur aura aussi fréquemment un manager très occupé qu’il consultera en allant à l’essentiel, optimisant le temps de chacun.

Voici quelques conseils pratiques qui font appel au bon sens.

1. Faites des emails courts, un par question

Avez-vous remarqué que, lorsque vous recevez un long pavé par email, vous n’y répondez souvent pas aussitôt. Privilégiez donc des emails courts quitte à faire plusieurs emails, un par question à poser. Les points les plus faciles à répondre trouveront ainsi une réponse très rapide et ne seront pas noyés au milieu d’un bloc compact.

2. Interrogez vous sur la pertinence de votre email

Il est tentant d’envoyer un email pour des détails mineurs. Les managers et statisticiens reçoivent quantités d’emails. Réfléchissez à deux fois avant d’envoyer un email. Si vous ne faites pas partie de ceux qui envoient des emails “à gogo”, votre interlocuteur prendra une attention à lire vos emails car il saura que ce sont des emails importants.

3. Optez pour un vocabulaire universel

Optez pour un vocabulaire non technique que vous parliez à un expert ou non. Au final, le message sera universel et pourra être transféré à d’autres interlocuteurs non prévus initialement. Evitez donc de nommer des noms de variables ou des procédures de manière brute. Rien, par contre, ne vous empêche de rajouter ces informations en complément.

4. Structurez votre email

Numérotez vos paragraphes : par soucis de clarté, ajoutez une numération. Cela sera très pratique lorsque votre email aura pour but de rappeler les points discutés avec votre interlocuteur.

Commencez par introduire le sujet : Votre destinataire travaille probablement sur d’autres sujets et n’a pas forcément en tête le projet qui vous concerne. Il est dont important d’introduire le sujet.

Faites force de proposition : Présentez les problèmes et listez aussi des actions possibles. Cela épargnera du temps à votre collaborateur qui n’aura plus qu’à prendre une décision.

Clarifiez votre attente envers votre destinataire : Finissez par une phrase qui définira clairement si vous attendez une réponse et si oui sur quel point en particulier. N’hésitez pas à mettre en valeur cette phase en changeant de couleur par exemple. 

Des mots-clés dans l’objet : Si votre email a un but purement informatif, précisez-le dans l’objet de votre email par le mot INFO. S’il s’agit d’un problème, vous avez le raccourci PBM pour attirer l’oeil du destinataire. Enfin précisez le nom de l’étude sur laquelle vous travaillez en plus du point particulier abordé dans l’email. 

5. Relisez-vous

Enfant, c’était ma grand-mère qui corrigeait mes cours avec son crayon papier taillé au couteau, lors que je lui les récitais mes leçons. Aujourd’hui, écrivant principalement en allemand et en anglais ce sont mes collègues qui me corrigent quand j’ai des messages ou documents importants à rédiger. Cela reste la meilleure manière de progresser dans la langue et d’éviter les malentendus.

Bien sûr, cette aide est à demander de manière ponctuelle et seulement après avoir fait des efforts :

  • avoir relu son travail auparavant
  • avoir passé son texte au correcteur de Word.

6. Tenez compte des contraintes techniques

Impression : votre email aura de grandes chances d’être imprimé. Evitez les images et tableaux trop larges. En dehors de votre premier contact où vos coordonnées complètes seront détaillées, privilégiez une signature courte. Cela évitera d’avoir le plus souvent une page de plus à l’impression juste pour la signature.

Pièce jointe : même si toute l’information est contenue dans une pièce jointe, sélectionnez l’extrait le plus important et copiez le dans l’email. Cela aidera le lecteur à classer votre mail : à répondre, à sauvegarder, etc. Par ailleurs, précisez dans le mail qu’il y a une pièce jointe pour qu’il la remarque. Si vous l’oubliez votre destinataire le remarquera et pourra vous prévenir.

N’hésitez pas à compléter la liste en envoyant un commentaire.

h1

Penser conditionnel (3/3) : CASE WHEN

juillet 3, 2008

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

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

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

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

Ressemblances :

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

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

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

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

2. La syntaxe CASE WHEN en exemple

2.1 Définir une variable à partir de plusieurs variables

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

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

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

2.2 Utiliser les fonctions

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

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

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

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

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

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

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

2.3 Créer une macro variable

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

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

h1

Des souvenirs de lycée, les logarithmes

juillet 2, 2008

Une des notations mathématiques qui est abordée au lycée en algèbre sont les logarithmes. Les propriétés de cette notation la rendent très attrayante pour exprimer et résoudre des équations. Mais vous souvenez vous du raisonnement qui se cache derrière ce nom ? Et savez-vous comment retrouver cette information en SAS ?

Cet article intéressera plus particulièrement ceux qui veulent replonger dans leur cours de statistique. En effet, les distributions statistiques, par exemple, sont formulées avec des équations contenant souvent des logarithmes. D’un point de vue professionnel, je n’ai jamais eu besoin de calculer un logarithme sous SAS pour l’industrie pharmaceutique.

1. Définition

Combien de fois faut-il multiplier 10 pour obtenir 1000 ? ou encore combien de fois faut-il multiplier 2 pour obtenir 32 ? Si vous avez la réponse à ces questions, vous êtes capable de résoudre des logarithmes.

Un logarithme est défini par une base. 10 et 2 sont les plus simples à comprendre dans un premier temps. Une base “e” rend les calculs plus simples. On parle alors de logarithme népérien ou logarithme naturel.

Dans le cas général, log symbolise le logarithme de manière général. Dans le cas particulier du logarithme népérien, log base e, le symbole est ln.

Les mathématiciens emploi plus facilement la base e dans la vie de tous les jours pour les raisons de facilité de calcul. Mais on a l’ordinateur de nos jours, me direz-vous. Alors il faut pensez au temps d’exécution de calculs complexes. Et là, même l’ordinateur sera content d’avoir des options pour résoudre le problème plus rapidement !

2. Exemples

Dans ce premier exemple, le logarithme de 1000 est défini par une base 10. Ainsi le but est de retrouver le nombre de fois 10 doit être multiplié pour obtenir le chiffre 1000. Sachant que 10×10x10=1000 ou de manière plus condensée 103=1000, la réponse est 3 fois.

log10 1000 = 3 car pour résoudre 10x=1000, on note x=3, soit 10×10x10=1000.

Dans ce second exemple, une base 2 est choisie. Il faut trouver le nombre de fois le nombre 2 est multiplié pour obtenir 32. La réponse est 5 fois.

log2 32 = 5 car pour résoudre 2x=32, on note x=5 soit 2×2x2×2x2=32.

Dans ce dernier exemple, une base e est choisie. Il s’agit du logarithme naturel ou logarithme népérien noté en langage courant ln. Pour retrouver la valeur approximative de e, on résout e1 sur son ordinateur ou sa calculatrice et on obtient une valeur de l’ordre de 2,71828.

loge 1 = ln 1 = 0 car pour résoudre ex =  1, on note x=0.

3. Calculer un logarithme en SAS

En SAS, il existe plusieurs types de fonctions LOG. Ainsi, notre log base 10 de 1000 devient LOG10 (1000) et notre log base 2 de 32 devient LOG2(32). Pour ce qui est du logarithme népérien, il suffit de ne pas préciser de chiffre LOG(1).

data _null_;
   log10_1000 = log10(1000);
   log2_32    = log2(32);
   loge_1     = log(1);
   loge_0     = log(0);
   put log10_1000 =;
   put log2_32    =;
   put loge_1     =   loge_0 = ;
run;

Dans l’exemple ci-dessus, j’ai arbitrairement choisi de ne pas créer de data set SAS en utilisant le mot _null_. Vous pouvez choisir de créer un data set et de l’afficher avec PROC PRINT.

Pour afficher les valeurs je me sers des instructions PUT. En choisissant d’ajouter le signe égal après le nom de la variable, non seulement la valeur des variables apparaîtront, mais aussi le nom des variables et le signe égal. Cela rend la lecture de l’information affichée dans la LOG plus facile. Faites le test sans le signe égal et vous verrez la différence dans la LOG.

Pour plus de précisions sur les fonctions logarithmiques, vous pouvez vous reporter à la documentation en ligne (SAS Online Doc. : LOG FunctionLOG10 FunctionLOG2 Function). Sachez par ailleurs qu’il existe d’autres fonctions log sous SAS : LOGBETA, LOGCDC, LOGPDF et LOGSDF.

h1

Des marges personnalisées pour vos rapports RTF

juin 30, 2008

Les documents lus par Word peuvent être sauvegardés au format RTF. SAS crée ce type de document en encadrant les tableaux et graphiques de la syntaxe ODS RTF (Output Delivery System). Par défaut, les marges sont de 0,63 cm (soit 0.25 inches) pour chacun des quatre côtés. Pour les changer, il faut procéder en 3 étapes : définir un template, changer les valeurs des marges et appeler le template.

1. Le coin des curieux

Un template est en programmation SAS ce qu’un patron est en couture. Il permet de définir l’apparence générale du travail final. Un template est défini en SAS avec la procédure PROC TEMPLATE. Pour distinguer les patrons pour les pantalons de ceux pour les chemisiers, des noms sont donnés à ces patrons. En SAS, ces noms sont appelés de STYLES.

Avec l’instruction LIST STYLES, vous affichez la liste des styles actuellement disponibles dans la fenêtre OUTPUT. Vous verrez notamment STYLES.RTF.

proc template;
   list styles;
run;

Pour voir le contenu de ce style dans la fenêtre LOG, il faut citer son nom dans l’instruction SOURCE.

proc template;
   source styles.rtf;
run;

Vous pourrez notamment repérer dans la LOG la partie sur les marges :

replace Body from Document
   “Controls the Body file.” /
   bottommargin = 0.25in
   topmargin = 0.25in
   rightmargin = 0.25in
   leftmargin = 0.25in;

2. Les trois étapes de base

2.1 Définir un template où les marges ne sont pas définies

Dans cet exemple, le nouveau template s’appelle STYLES.SASREF_RTF. Il est défini à partir du style STYLES.RTF. Les marges sont définies dans BODY FROM DOCUMENT. Une valeur non définie est assignée aux marges grâce au mot _UNDEF_ (undefined). Pour terminer la définition du template, une instruction END est ajoutée.

proc template;
   define style styles.sasref_rtf;
      parent = styles.rtf;
      replace body from document /
          bottommargin = _undef_
          topmargin = _undef_
          rightmargin = _undef_
          leftmargin = _undef_;
   end;
run;

L’ODS LISTING permet de désactiver la sortie vers la fenêtre OUTPUT dans un premier temps puis de la réactiver. Le mot-clé OUTPUT étant déjà pris au moment de la création de l’instruction ODS LISTING, SAS a choisi le mot-clé LISTING pour désigner la fenêtre OUTPUT.

2.2 Changer les mesures avec l’instruction OPTIONS

A présent, il est possible de modifier les marges avec l’instruction OPTIONS.

options bottommargin = 1.5 cm
        topmargin    = 1.5 cm
        rightmargin  = 2 cm
        leftmargin   = 2.5 cm;

2.3 Appeler le template nouvellement créé

Une option STYLE= est ajoutée à l’instruction ODS RTF. Le nom du template nouvellement créé y est assigné.

ods listing close;
ods rtf file  = ‘C:/sasref/margin_eg.rtf’
        style = styles.sasref_rtf;
   proc print data=sashelp.class;
   run;
ods rtf close;
ods listing;

3. Etape de nettoyage

Pour terminer, si le template n’est pas amené à être réutilisé, l’instruction DELETE permettra de le supprimer.

proc template;
   delete styles.sasref_rtf;
run;

h1

Penser conditionnel (2/3) : SELECT

juin 26, 2008

Pour dire à SAS quelles actions sont à mener si des critères sont remplis, nous avons vu la syntaxe IF/THEN/ELSE (voir article). Dans un data step, l’alternative à cette syntaxe, SELECT WHEN, fait l’objet du présent article.

1. La syntaxe de base

Toutes les conditions sont englobées entre l’instruction SELECT et l’instruction END.  Chaque condition est introduite par l’instruction WHEN. Les observations non sélectionnées avant la fin sont traités par l’instruction OTHERWISE.

A la différence de la syntaxe IF/THEN :

  • Les conditions sont listées entre parenthèses et aucun mot-clé n’introduit l’action.
  • Si toutes les conditions se basent sur une seule variable, celle-ci peut-être citée une seule fois et ce en tout début dans l’instruction SELECT. Mais il faut aussi que les valeurs prises par la variable soient toutes listées. Ainsi <5 ne marche pas mais 0,1,2,3,4 marche.

De la même manière que IF/THEN :

  • Seuls les records non sélectionnés pas un précédent WHEN sont considérées par les conditions suivantes. C’est le même principe que le ELSE IF.
  • Si plusieurs actions sont planifiées, celles-ci sont listées entre un DO et un END.

select  <nom_variable, optionnel> ;
   when (<condition>) 
      do;
         <action 1>;
         <action 2>;
         *etc;
       end;
   when (<condition>)  <action>;
   otherwise <action>;
end;

2. Le caractère unique du SELECT WHEN

Pas d’action s’il vous plaît : Lorsqu’il n’y a aucune action pour une condition donnée, il est possible d’écrire une instruction WHEN sans donner de détails après la parenthèse. On parle d’instruction nulle.

OTHERWISE est parfois obligatoire : Si aucune condition n’est rempli pour un data set donné, il est important d’avoir une instruction OTHERWISE. Celle-ci peut rester vide d’action.

3. Illustration par un exemple 

Premier exemple : les trois caractéristiques de ce premier exemple sont les suivantes.

  • La condition est basée sur une seule variable. On choisi dont de nommer une seule fois cette variable dans l’instruction SELECT.
  • Il y a plusieurs actions (DO/END) pour certaines conditions. 
  • Dans le cas où aucune des conditions précédentes ne serait remplie, l’instruction OTHERWISE est ajoutée.

Les records incluant un âge manquant sont sauvegardées dans le data set nommé MISS_AGE et la  date de création d’une requête (query) pour clarifier le record est ajoutée dans une variable QUERY_SDT (Query Starting Date). Les autres records, traitant des moins de 5 ans, sont sauvegardés dans le data set YOUNG.

data miss_age young ;
   set sashelp.class;
   select (age);
      when (.)
         do;
            query_sdt=mdy(3,26,2008);
            output miss_age;
         end;
      when (0,1,2,3,4) output young;
      otherwise;
   end;
run;

Second exemple : cet exemple se distingue sur trois aspects.

  • La condition est basée sur plusieurs variables. Il faut dont les lister à chaque nouvelle instruction WHEN.
  • Une seule action n’est donnée à chaque fois voir moins. L’action porte sur la valeur de la variable POP. Il n’y a pas d’action quand l’âge n’est pas une valeur connue ou que le sexe n’est pas défini par les lettres majuscules F (female) ou M (male).
  • Les valeurs restantes se rapportent aux hommes ayant une valeur pour leur âge. C’est notre troisième population.

data pop;
   set sashelp.class;
   select;
      when (age > 13 and sex=‘F’) pop = 1;
      when (age >= 0 and sex=‘F’) pop = 2;
      when (age < 0 or sex not in (‘F’,‘M’));
      otherwise pop = 3;
   end
run;

A dans huit jours pour une présentation du CASE WHEN de la procédure SQL.

h1

Il était une fois la LOG

juin 23, 2008

La fenêtre LOG (ou JOURNAL pour la version française de SAS) contient des informations plus ou moins détaillées sur le travail effectué par SAS. Ces informations peuvent être sauvegardées dans un fichier externe ou être supprimées lors de l’exécution du programme.

1. Une LOG plus ou moins détaillée

Deux situations se présentent :

  • lire les détails de l’exécution d’une macro
  • accéder aux détails d’un fichier .sas inclus dans un autre programme (%INCLUDE…)

Changer les options par défauts : les options MPRINT, MLOGIC et SYMBOLGEN s’adresse à la macro et SOURCE2 au programme inclus. Par défaut, ces options sont désactivées. Elles ont pour but d’aider le programmeur au stade du développement.

Voir le statut actuel des options : pour connaître l’état actuel d’une de ces options, il faut consulter la log après avoir exécuté la procédure options.

proc options;
run;

Remettre les options dans leur état initial : pour désactiver ces options, on utilise NOMPRINT, NOMLOGIC, NOSYMBOLGEN et NOSOURCE2.

Exemple, partie 1 : Le fichier main_include.sas contient l’instruction OPTIONS, le format AGE et la macro RAPPORT.

options source2 mprint mlogic symbolgen;

proc format;
   value age
   11-13 = ‘11-13′
   14-16 = ‘14-16′
   other = ‘Autre’;
run;

%macro rapport (dsn=);
proc report data=&dsn;
   columns name age sex;
   define name /‘Nom’ display;
   define age  /‘Age’ display ;
   define sex  /‘Sexe’ display;
   format age age.;
run;
%mend rapport;

Exemple, partie 2 : Dans un second programme, le premier programme et la macro RAPPORT sont appelés.

%include ‘C:/sasref/main_include.sas’;
%rapport (dsn=sashelp.class);

2. Commander la suppression du contenu de la LOG

Sous Windows, par défaut, à chaque nouvelle exécution d’un programme, la log grossie. Pour la vider, il y a deux possibilités : une manuelle et une automatique.

Après avoir activé la fenêtre log en la sélectionnant, il y a trois choix possibles :

  • Combiner les touches clavier Ctrl et E (raccourci clavier CTRL+E)
  • Sélectionner menu Edit/Clear All.
  • Taper la commande log;clear; dans le cadre en haut à gauche de l’écran

Cela marche aussi avec les fenêtres OUTPUT et EDITOR. Remplacez seulement le mot LOG par OUTPUT ou EDITOR pour la commande.

Pour une action automatique, l’instruction DM permet d’inclure dans le programme les mots-clés donné jusqu’à présent dans le cadre pour les commandes.

proc print data=sashelp.class;
run;

dm ‘log;clear;’;

3. Sauvegarder le contenu de la LOG dans un fichier externe

Rediriger le contenu de la log : la procédure PROC PRINTTO permet de rediriger le contenu de la log dans un fichier externe. Pour cela, le nom du fichier à créer et son chemin d’accès sont définis dans LOG=. Au choix, l’extension du fichier est .log ou .txt.

Rediriger le listing : le contenu de la fenêtre OUTPUT peut-être aussi redirigé. Cette fois-ci, il faut utiliser FILE=.

Ecraser les anciens fichiers : pour effacer le contenu d’un précédent fichier, il y a l’option NEW dans l’instruction PROC PRINTTO.

Réinitialisation : pour réactiver les destinations par défaut, la procédure sans argument est soumise au SAS.

proc printto log=‘C:/sasref/class.log’ new;
run;

proc printto file=‘C:/sasref/class.txt’ new;
run;

proc print data=sashelp.class;
run;

proc printto;
run;

h1

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

juin 19, 2008

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

SAS propose plusieurs syntaxes pour exprimer ces conditions.

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

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

1. Le minimum ou presque

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

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

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

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

2. Multiplier les combinaisons

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

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

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

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

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

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

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

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

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

3. Parenthèse sur les valeurs manquantes 

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

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

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

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

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

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

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

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

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

h1

Mes valeurs sont t’elles proches de la moyenne ? (écart-type)

juin 17, 2008

Pour résumer une série de mesures, il est courant de proposer la moyenne. Mais avoir une moyenne de 11 n’a pas le même sens selon que les valeurs soient dispersées entre 10 et 13, ou entre 0 et 20. Dans le premier cas, toutes les valeurs sont plus proches de la moyenne que dans le second cas. L’écart-type (ou standard deviation en anglais) reflète cette subtilité. Le statisticien aura pour rôle d’interpréter cette valeur. En comprenant le sens d’un écart-type,  le programmeur trouvera un outil supplémentaire pour vérifier la cohérence de ses résultats.

1. Des variables continues

La moyenne et l’écart-type sont des outils s’appliquant uniquement aux données numériques, suivant un ordre donné où l’écart entre chacune des valeurs potentielles est toujours le même. On peut donc parler de valeurs continues au sens large du terme.

Ainsi, l’âge d’une personne est une donnée continue qu’elle soit arrondie en années, en mois, en jours, en heure. La moyenne et l’écart-type auront une précision similaire.

2. Définition l’écart-type d’une population

L’écart-type ayant pour but de chiffrer l’écart entre les valeurs  et la moyenne. Il est donc logique de calculer la différence entre chaque valeur et la moyenne. Dans un premier temps, on a autant de différences que de valeurs. Dans un second temps, une valeur moyenne est extraite de ces différences.

1. Mettre au carré les différences : qui dit moyenne, dit somme des valeurs divisé par le nombre de valeur. Hors, la somme de valeurs positives et négatives s’annulent. Et dans notre cas, on a bien des valeurs inférieures et des valeurs supérieures à la moyenne. Dans le cas de l’écart-type, toutes les différences sont rendues positives en les multipliant par elles-mêmes (mises au carré).

C’est probablement pour des faciliter la résolution de calculs mathématiques que la mise au carré est préféré à la prise des valeurs absolu. Si vous avez une autre hypothèse, n’hésitez pas à en faire part.

2. Extraire la moyenne : on souhaite une moyenne. Donc la somme des différences (mises au carré) sont divisées par le nombre de différences. Si on s’arrête là, la statistique s’appelle la variance.

3. Exprimer la dispersion dans la même unité que la moyenne : A présent la somme des différences n’est plus dans la même unité que la moyenne. Pour parler dans la même unité, on prend la racine de l’ensemble du calcul.

3. Estimer l’écart-type d’une population à partir d’un échantillon

Contexte : il est fréquent de ne pas travailler sur la population qui nous intéresse mais sur un échantillon. Par exemple, si on mesure la pression artérielle systolique des patients d’une étude clinique pour savoir si la drogue a permis de la réduire, le statisticien n’est pas intéressé par la moyenne de ces patients mais bien celle de tous les personnes pouvant à l’avenir faire appel à cette drogue.

Le problème : De plus, les recherches statistiques ont permis de démontrer qu’en moyenne, la moyenne de tous les échantillons possibles est la même que celle de la population. Pour l’écart-type, c’est un peu moins simple, puisqu’il la moyenne des écarts-types de tous les échantillons n’est pas exactement égale à celle de la population.

La solution : Mais les chercheurs en statistique sont là ! Ils ont réussi à montrer qu’en enlevant 1 au nombre total de valeurs dans chacun des échantillons, on pouvait retrouver l’écart-type de la population (cf. des cours d’inférence qui semble si théorique au prime abord mais qui permettent d’accéder à l’arrière de la scène).

Vocabulaire : Et pour enrichir votre vocabulaire et surtout comprendre ces spécialistes sachez que si l’écart-type sera appelé un estimateur biaisé si le 1 n’est pas enlevé.

L’écart-type le plus utilisé est donc le second, celui où on divise les différences non pas par le nombre de différences mais le nombre de différences moins 1.

4. Comprendre la différence entre l’écart-type et l’erreur-type

Pour ceux qui auront une formation à composante statistique, vous pourrez être amené à expliquer en entretien ou à vos collègues la différence entre l’écart-type (standard deviation) et l’erreur-type (standard error). 

La première différence, c’est que l’écart-type s’applique à des données, alors que l’erreur-type s’applique à la statistique de la moyenne. 

A chaque fois, qu’un échantillon est pris, sa moyenne va servir à estimer la moyenne de la population. Bien-sûr, toutes les moyennes des échantillons ne sont pas identiques. Il existe une variabilité. Certains sont plus proches de la réalité que d’autre. Cette variabilité des résultats entre les échantillons est donnée par l’erreur-type. Ainsi un intervalle à l’intérieur duquel la moyenne de la population se tient pourra être estimé.

5. En langage mathématique, l’écart-type donne quoi ?

Pour désigner nos valeurs, le mathématicien utilise la lettre X.

  • Xi représente la ième valeur de l’échantillon. Si on a 15 valeurs alors i prend les valeurs de 1 à 15 ou plus généralement les valeurs de 1 à n.
  • La moyenne de ces Xi est symbolisée par un X avec une barre au dessus.

Pour calculer l’écart-type, on a parlé de trois étapes :

  1. sum(Xi-Xbar)2 Tout d’abord la différence entre chaque Xi et la moyenne X barre est calculée. Elles sont mises au carré. Puis, la somme de ces valeurs en est faite. On en profite pour préciser que les valeurs de i vont de 1 à n.
  2. sum(Xi-Xbar)2 / (n-1) Après, il s’agit de calculer la moyenne de ces valeurs
  3. racine(sum(Xi-Xbar)2 / (n-1)) Enfin, la statistique est convertie en une unité comparable à celle de la moyenne via la racine carré.

6. Et en langage SAS, comment trouver la valeur d’un écart-type ?

Dans tous les cas suivant, le dénominateur est n-1.

6.1 Fonction STD : La fonction STD (standard deviation) retourne la valeur de l’écart-type.

proc sql;
   select std(age) as std_age
   from sashelp.class;
quit;

6.2 Calcul manuel : dans un premier temps, la différence avec l’âge moyen est calculée pour chaque record. Chaque différence est mise au carré. Dans un deuxième temps, la somme de ces différences est divisée par le nombre de records moins 1. Enfin, la racine carrée du tout est prise.

proc sql;
   create table step1 as
      select (age-mean(age))**2 as step1
      from sashelp.class;
   select sqrt(sum(step1)/(count(*)-1)) as step2_3
      from step1;
quit;

6.3 Les procédures PROC MEANS et PROC SUMMARY : dans les exemples ci-dessous, j’ai volontairement choisi l’instruction ODS OUTPUT pour extraire les statistiques dans un data set.

proc means data=sashelp.class;
var age;
ods output Summary=proc_means;
run;

proc summary data=sashelp.class print;
   var age;
   ods output Summary=proc_summary;
run;

6.4 La procédure PROC UNIVARIATE : deux sorties fournies par la procédure UNIVARIATE sont indifféremment disponible.

proc univariate data=sashelp.class;
   var age;
   ods output Moments=proc_univ_opt1;
   ods output BasicMeasures=proc_univ_opt2;
run;

h1

Jongler avec les records grâce aux compteurs

juin 12, 2008

Sous SAS, une variable compteur permet de numéroter les lignes d’observations. Le plus souvent, cette variable sert ensuite à sélectionner certaines lignes d’un jeu de données et d’agir en fonction. Par exemple, pour chaque patient, un fois le compteur créé, il est simple de sélectionner les 5 premiers records.

Pour développer une variable compteur, il faut maîtriser la notion de FIRST. Vous pouvez vous reporter à l’article “Repérer les 1ers/derniers records (FIRST/LAST)”.

En outre, il faut comprendre la notion de RETAIN. Celle-ci sera abordée dans cet article.

Quatre exemples serviront à illustrer le sujet. Ils sont basés sur un data set nommé LAB ayant 9 lignes observations. Il est donné en fin d’article dans le paragraphe “Annexe”. On y trouve trois patients (PAT_ID), deux types de tests médicaux (TEST) et une date pour chaque test (variable TEST_DT). La variable compteur s’appelle à chaque fois CNT.

 1. La notion de RETAIN

Un RETAIN permet d’assigner une valeur à toutes les observations d’une variable. On préfèrera donc un RETAIN à ”variable=valeur;” pour assigner une valeur unique pour toutes les records d’une variable données. 

Si entre temps, la valeur d’une observation est modifiée, tous les valeurs suivantes prennent cette nouvelle valeur. Cette seconde fonctionnalité sert pour créer une variable compteur.

Un RETAIN se définit le plus souvent dans une instruction RETAIN. Dans le cas des compteurs, on peut créer un RETAIN implicite prenant une valeur d’origine de zéro.

2. Pour chaque nouvelle observation incrémenter le compteur : dans ce premier exemple, à chaque nouvelle observation identifiée de manière unique par PAT_ID, TEST_DT et TEST, le compteur est incrémenté par 1. Le compteur va alors de 1 à 9 (le total d’observations). Les données sont préalablement triées par ces trois variables.

  test_dt    pat_id    test    cnt

28MAR2006      101     DBP      1
28MAR2006      101     SBP      2
29APR2006      101     DBP      3
27MAY2006      101     SBP      4
23JUN2006      101     SBP      5
13JAN2006      301     DBP      6
14FEB2006      301     SBP      7
15MAR2006      301     DBP      8
05MAR2006      401     DBP      9

Il faut donc dans un premier temps trier les données et rappeler cet ordre dans l’instruction BY du data step.

proc sort data=lab;
   by pat_id test_dt test;
run;

Puis la variable CNT prend une valeur de 0 pour chaque record.

Enfin les records sont lus les uns après les autres. A chaque nouvelle TEST pour un PAT_ID et TEST_DT donné, le compteur est incrémenté de 1.

data lab;
   retain cnt 0;
   set lab;
   by pat_id test_dt test;
   if first.test then cnt=cnt+1;
run;

Un RETAIN implicite : l’instruction RETAIN peut-être omise si un RETAIN implicite est utilisé. C’est le cas ici quand “cnt=cnt+1″ est remplacé par “cnt+1″.

data lab;
   set lab;
   by pat_id test_dt test;
   if first.test then cnt+1;
run;

3. Pour chaque nouvelle date, incrémenter le compteur : dans le second exemple, pour chaque nouvelle date indépendamment du patient ou de type de test, le compteur est incrémenté par 1. Le compteur va de 1 à 8 (les 8 différentes dates). Les données sont triées par date au préalable.

  test_dt    pat_id    test    cnt

13JAN2006      301     DBP      1
14FEB2006      301     SBP      2
05MAR2006      401     DBP      3
15MAR2006      301     DBP      4
28MAR2006      101     SBP      5
28MAR2006      101     DBP      5
29APR2006      101     DBP      6
27MAY2006      101     SBP      7
23JUN2006      101     SBP      8

proc sort data=lab;
   by test_dt;
run;

data lab;
   set lab;
   by test_dt;
   if first.test_dt then cnt+1;
run;

4. Pour chaque nouveau patient, incrémenter le compteur : dans ce troisième exemple, chaque patient reçoit un numéro unique allant de 1 à 3 ; trois étant le nombre total de patients. Les données sont donc triées par PAT_ID.

   test_dt    pat_id    test    cnt

28MAR2006      101     SBP      1
28MAR2006      101     DBP      1
27MAY2006      101     SBP      1
23JUN2006      101     SBP      1
29APR2006      101     DBP      1
14FEB2006      301     SBP      2
13JAN2006      301     DBP      2
15MAR2006      301     DBP      2
05MAR2006      401     DBP      3

proc sort data=lab;
   by pat_id;
run;

data lab;
   set lab;
   by pat_id;
   if first.pat_id then cnt+1;
run;

5. Pour chaque nouveau date d’un patient donné, incrémenter le compteur : dans ce dernier exemple, à chaque nouvelle date, le compteur est incrémenté par un. Le premier patient ayant 4 dates différentes et 5 observations, le compteur va de 1 à 4 pour lui. Une des valeurs est doublée pour la date identique. Le second patient ayant trois dates uniques, le compteur va de 1 à 3 pour lui. Le compteur est donc réinitialisé à 1 pour chaque nouveau patient.

  test_dt    pat_id    test    cnt

28MAR2006      101     SBP      1
28MAR2006      101     DBP      1
29APR2006      101     DBP      2
27MAY2006      101     SBP      3
23JUN2006      101     SBP      4
13JAN2006      301     DBP      1
14FEB2006      301     SBP      2
15MAR2006      301     DBP      3
05MAR2006      401     DBP      1

proc sort data=lab;
   by pat_id test_dt;
run;

data one;
   set orig;
   by pat_id test_dt;
   if first.pat_id then cnt=1;
   else if first.test_dt then cnt+1;
run;

Annexe :

data orig;
   format test_dt date9.;
   input pat_id test_dt date9. test_type $;
   datalines;
101 28MAR2006 SBP
101 28MAR2006 DBP
101 27MAY2006 SBP
101 23JUN2006 SBP
301 14FEB2006 SBP
101 29APR2006 DBP
301 13JAN2006 DBP
301 15MAR2006 DBP
401 05MAR2006 DBP
;
run;
  

 

 

h1

Insérer quelques nouvelles observations

juin 9, 2008

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

h1

Savoir interpréter une note liée au MERGE

juin 5, 2008

Dans un cas particulier, une jointure many-to-many avec un MERGE, SAS génère une note. Il est très important de savoir l’interpréter. En effet, il est fréquent de vouloir un FULL JOIN (PROC SQL) mais d’utiliser maladroitement le MERGE (Data Step). Je vous propose donc de voir la différence entre les deux approches.

Rappel : si dans chacun des deux data sets à fusionner, il y a des doublons pour les variables communes, il s’agit d’une jointure MANY-TO-MANY.

Données utilisées pour illustrer le sujet : voici deux data sets appelés FRST_MANY et SECOND_MANY avec chacun trois variables. Les variables X et Y sont présentes dans les deux data sets. Dans le premier data set, trois lignes d’observations ont pour valeur x=A, y=B. Dans le second data set, deux lignes d’observations ont pour valeurs x=A, y=B et deux autres x=B, y=D.

 frst_many       second_many
 a    x    y     x    y    b
 1    A    B     B    D    2
 2    A    B     B    D    8
 9    A    B     A    B    3
 3    C    D     A    B    4
 5    B    D     E    F    6

1. Premier Choix, le FULL JOIN de la PROC SQL : on veut que chaque ligne d’observations de FRST_MANY soit dupliquée s’il y a plusieurs lignes d’observations dans SECOND_MANY ayant les mêmes BY variables ; et inversement.

En d’autres termes, vu que x=A, y=B apparaît trois fois dans le premier data set et deux fois dans le second, il y aura six lignes d’observations après la fusion des jeux de données.

De même, vu qu’il y a une observation x=B, y=D dans le premier jeu et deux dans le second jeux, il y aura deux observations après la fusion et la variable a=5 du premier jeux sera dupliquée pour chaque ligne.

      final
 a    x    y    b
 1    A    B    3
 2    A    B    3
 9    A    B    3
 1    A    B    4
 2    A    B    4
 9    A    B    4
 5    B    D    2
 5    B    D    8
 3    C    D    .
 .    E    F    6

En terme de programmation SAS, cela donne :

proc sql;
   create table final as
   select a,
          coalesce(a.x,b.x) as x,
          coalesce(a.y,b.y) as y,
          b
   from   frst_many a
   full join
          second_many b
   on     a.x=b.x and
          a.y=b.y;
quit;

2. Second Choix, MERGE : pour chaque combinaison de BY variables, le nombre de lignes dans le data set final correspond au nombre de ligne le plus important parmi les deux data sets d’origine.

Dans ce cas, SAS génère la note suivante, très importante :

NOTE: MERGE statement has more than one data set with repeats of BY values.

Le mieux est encore de regarder l’exemple pour comprendre ce qui se passe.

Vu qu’il y a trois lignes d’observations pour x=A, y=B dans le premier jeu, et seulement deux dans le second, il y aura trois lignes d’observations au final pour ces BY variables. La deuxième et dernière valeur de la variable b du second data set (b=3) sera dupliquée pour les lignes supplémentaires.

Vu qu’il y a deux lignes d’observations pour x=B, y=D dans le second jeu et une seule dans le premier, la valeur de la variable a du premier data set (a=5) sera également dupliquée pour la ligne supplémentaire.

      final
 a    x    y    b
 1    A    B    4
 2    A    B    3
 9    A    B    3
 5    B    D    2
 5    B    D    8
 3    C    D    .
 .    E    F    6

Pour obtenir ce résultat, il faut passer par un MERGe et si besoin trier les données :

proc sort data=frst_many;
   by x y;
run;

proc sort data=second_many;
   by x y;
run;

data final;
   merge frst_many
         second_many;
   by x y;
run;

 

Annexe : syntaxe pour créer les data sets et ainsi tester la PROC SQL et le MERGE.


data frst_many;
   input a x $ y $;
   datalines;
1 A B
2 A B
9 A B
3 C D
5 B D
;
run;

 

data second_many;
   input x $ y $ b;
   datalines;
B D 2
B D 8
A B 4
A B 3
E F 6
;
run;

h1

Améliorer l’habillage de vos tableaux (débuter avec PROC TEMPLATE via PROC REPORT)

juin 2, 2008

La syntaxe ODS (Output Delivery System) de SAS fait appel à des templates pour définir la mise en forme des tableaux, graphiques à publier. Dans le cas présent, il s’agira de définir un template qui s’appliquera à tous les tableaux générés par un PROC REPORT. Les styles caractérisant les templates sont définis avec la procédure PROC TEMPLATE. Tout d’abord, il s’agit de savoir comment appliquer les styles sans template pour un seul PROC REPORT et ainsi se familiariser avec la syntaxe.

1. Le tableau par défaut

Le programme suivant créé un document RTF (CLASS_V1.RTF) contenant un tableau avec 5 colonnes. Les données proviennent du data set CLASS de la bibliothèque SAS.

ods rtf file = ‘C:/sasreference/class_v1.rtf’;
proc report data=sashelp.class nowd;
   columns sex name age height weight;
   define sex    / display ‘Sexe’;
   define name   / display ‘Nom’;
   define age    / display ‘Age’;
   define height / display ‘Taille’;
   define weight / display ‘Poids’;
run;
ods rtf close;

Le tableau est quadrillé. Les lettres sont alignées à gauche et les chiffres à droite. Le nom des colonnes ont un fond grisé et sont mises en gras. Le tout a une police Times New Roman de taille 10pt.

2. Des styles pour trois destinations différentes

Dans PROC REPORT, on peut ajouter des options au niveau de l’instruction PROC REPORT pour appliquer le résultat à l’intégralité de la table ou dans une instruction DEFINE en particulier pour agir sur une colonne. Il est possible de grouper les deux méthodes. Par exemple, on peut choisir d’avoir des colonnes de trois centimètres partout sauf dans une colonne.

  • STYLE(COLUMN) : pour changer les informations au niveau des colonnes, c’est-à-dire les données sans le titre, on ajoutera STYLE(COLUMN)=[...] dans l’instruction DEFINE.
  • STYLE(HEADER) : pour modifier les caractéristiques des noms de colonnes, les headers, il faudra utiliser STYLE(HEADERr)=[...]
  • STYLE(REPORT) : pour définir les bordures, leur position, couleur et épaisseur, et les espaces entre les cellules, STYLE(REPORT)=[...] est utilisé dans l’instruction PROC REPORT.

3. De multiples options

Les options sont listées dans les crochets, Un espace sert de séparateur entre les options. Voici un aperçu de ces options:

3.1 Agir sur le texte

  • FONT_FACE= ou comment définir une police différente de Times : pour changer la police en Arial, on fait appel à FONT_FACE=’Arial’.
  • FONT_SIZE= ou comment opter pour une taille de caractères différente de 10pt : pour changer la taille du texte en 12, cela donne FONT_SIZE=12pt.
  • FONT_WEIGHT ou comment jongler entre gras et normal : pour mettre en gras, on utilisera FONT_WEIGHT=BOLD. Si au contraire est déjà en gras, et qu’on souhaite le remettre en normal, il faut choisir FONT_WEIGHT=MEDIUM.
  • FOREGROUND= ou comment changer la couleur du texte : l’option FOREGROUND= sert à définir la couleur du texte. Ainsi FOREGROUND=DARKBLUE mettra le texte en bleu foncé.

3.2 Agir sur la position du texte

  • JUST= ou comment changer l’alignement en largeur du texte dans une cellule : par défaut les lettres sont alignés à gauche et les nombres sont alignés à droite. Pour définir le même alignement partout et ensuite changer ponctuellement si besoin, il y a JUST=. Ainsi, JUST=C (center) centre, JUST=R (right) aligne à droite et JUST=L (left) aligne à gauche.
  • VJUST= ou comment changer l’alignement vertical du texte dans une cellule : si le texte d’une case s’étend sur plusieurs lignes, celui des autres cellules est aligné vers le haut. Pour changer l’alignement, on utilise VJUST=BOTTOM.

3.3 Changer la couleur de fond

  • STYLE(COLUMN)=[BACKGROUND=...] ou comment changer le fond des cellules contenant les observations.
  • STYLE(HEADER)=[BACKGROUND=...] ou comment changer la couleur de fond des titres des colonnes.
  • STYLE(REPORT)=[BACKGROUND=... ] ou comment changer l’arrière plan : défini dans STYLE(REPORT), la couleur s’applique à l’arrière du tableau. Si l’espace qui sépare les cellules n’est pas de zéro (CELLSPACING), cette couleur de fond apparaît. Par défaut la couleur noir apparaît entre les cellules. On peut soit changer la couleur pour blanc (BACKGROUND=WHITE) ou réduire l’espace entre les cellules à zéro (CELLSPACING=0).
  • CELLWIDTH= ou comment définir la largeur des colonnes : la largeur de toutes les cellules d’une colonne est défini par CELLWIDTH. Cela donne CELLWIDTH=3cm.

3.4 Agir sur les bordures

  • BORDERCOLOR= ou comment changer la couleur des bordures
  • BORDERWIDTH= ou comment changer  la largeur des bordures du cadre (frame).
  • FRAME= ou comment décider quels côtés du cadre doivent apparaître : on distingue huit valeurs pour FRAME :
    • BOX garde tout le cadre extérieur
    • VOID enlève les bords du cadre
    • HSIDES (horizontal side) garde les deux côtés horizontaux
    • VSIDES (vertical side) garde les deux côtés verticaux
    • ABOVE garde la ligne du dessus,
    • BELOW garde la ligne du dessous
    • LHS (left hand side) garde le côté gauche
    • RHS (right hand side) garde le côté droite
  • RULES= ou comment décider quelles lignes à l’intérieur du tableau doivent être visible : on a cinq valeurs à disposition pour RULES :
    • NONE (none ou aucun) enlève toutes les lignes intérieures
    • ROWS (row ou ligne) ne garde que les lignes horizontales
    • COLS (column ou colonne) ne garde que les lignes verticales
    • GROUP ne garde que la ligne séparant les titres de colonnes, des observations.

Voici donc un schéma récapitulalif des combinaisons de FRAME et RULES lorsque, dans STYLE(REPORT), BACKGROUND=WHITE ou CELLSPACING=0. Pour facilité la lecture, l’effet de FRAME est en noir et celui de RULES est en rouge.

*NB: Cette image contient une erreur : remplacez grps par group.

4. L’effet final avec les options de PROC REPORT

Voici un résumé de l’Exemple ci-dessous :

  • Seules les bordures du haut et du bas sont gardées (FRAME=HSIDES), et épaissie (BORDERWIDTH=.2cm) après avoir mis en blanc l’arrière plan du tableau pour qu’il n’apparaisse pas entre les cellules (BACKGROUND=WHITE). On choisi de séparer les titres des valeurs par une ligne  (RULES=GROUPS) et de mettre tous les trais en gris (BORDERCOLOR=GRAY).
  • Au niveau des titres, la couleur de fond est enlevée (BACKGROUND=WHITE).  Une police Arial de 12pt non gras est choisie.
  • Enfin au niveau des données, la police est également Arial de taille 12pt. Les colonnes sont de 3 cm de largeur et le texte est aligné à droite.

ods rtf file  = ‘C:/sasreference/final_v1.rtf’
        style = sasref;

proc report data=sashelp.class nowd
   style(report)=[rules       = groups
                  frame       = hsides
                  background  = white
                /*cellspacing = 0*/
                  bordercolor = gray
                  borderwidth = .2cm]
   style(header)=[background  = white
                  font_size   = 12pt
                  font_face   = 'Arial'
                  font_weight = medium]
   style(column)=[font_size   = 12pt
                  font_face   = 'Arial'
                  cellwidth   = 3 cm
                  just        = r];
   columns name sex age height weight;
   define name   / display ‘Nom’;
   define sex    / display ‘Sexe’;
   define age    / display ‘Age’;
   define height / display ‘Taille’;
   define weight / display ‘Poids’;
run;

ods rtf close;

5. Obtenir le même résultat avec un proc template

 A présent que vous avez vu les différentes régions sur lesquelles vous pouvez agir et une grande partie des options que vous pouvez changer, voici la syntaxe de PROC TEMPLATE.

Ici, le nouveau template s’appelle SASREF (DEFINE STYLE). Il est basé sur le style par défaut (PARENT=).

proc template;
   define style styles.sasref;
   parent = styles.default;
   /*.à compléter..*/
   end;
run;

Vous remarquerez que les informations listées dans REPLACE TABLE sont les mêmes que dans notre précédent ODS(REPORT). Celles listées dans REPLACE HEADER correspondent à celle de ODS(HEADER) et enfin celle de REPLACE DATE sont identiques à ODS(COLUMN).

proc template;
   define style styles.sasref;
   parent = styles.default;
   replace table /  rules       = groups
                    frame       = hsides
                    background  = white
                  /*cellspacing = 0*/
                    bordercolor = gray
                    borderwidth = .2cm;
   replace header / foreground  = black
                    background  = white
                    font_size   = 12pt
                    font_face   = ‘Arial’
                    font_weight = medium;
   replace data   / background  = white
                    font_size   = 12pt
                    font_face   = ‘Arial’
                    cellwidth   = 3 cm
                    just        = r;
   end;
run;

Vous noterez en plus l’utilisation de FOREGOUND dans REPLACE HEADER et BACKGROUND dans REPLACE DATA. En effet, si vous appelez le template sans les instructions REPLACE, SAS ajoute un font gris aux données et met les titres en bleu.

A présent, il s’agit de faire référence à ce template dans l’instruction ODS RTF.

ods rtf file  = ‘C:/sasreference/class_v1.rtf’
        style = sasref;

Avant de terminez, il vous faudra supprimer le template

proc template;
   delete styles.sasref;
run;