Archive for the ‘SAS intermédiaire’ Category

h1

SAS : obtenez des couleurs sympas dans vos rapports en 5 minutes

août 20, 2018

h1

A partir de quelle lettre y a-t-il une différence : la fonction compare

mai 25, 2015

La fonction COMPARE retourne le nombre zéro si aucune différence n’existe entre deux chaînes de caractères. Sinon elle retourne la position la position du premier caractère différent.

Dans l’exemple ci-dessous, deux datasets sont créés. Une fois combinés, on s’intéresse à la différence entre la variable LABEL_ONE du premier dataset et la variable LABEL_TWO du second dataset. La première différence a lieu sur la deuxième lettre. La variable DIFF prend donc la valeur 2.

data one;
   length start $8 label_one $8;
   start='1';
   label_one='ABC';
run;

data two;
   length start $8 label_two $8;
   start='1';
   label_two='AbC';
run;

data diff;
   merge one two;
   by start;
run;

data diff;
   set diff;
   diff=compare(label_one,label_two);
run;

proc print data=diff;
run;

Vous pouvez ajouter un troisième paramètre dans la fonction si vous ne voulez pas tenir compte des différences de majuscule, de blancs de début de chaîne de caractère,…

Dans quel cas utiliser cette fonction ? Si vous réalisez un rapport listant la différence entre deux valeurs pour pouvoir ensuite les corriger, vous pouvez utiliser cette fonction pour préciser à partir de quel moment la couleur devra changer.

Pour en savoir plus : la documentation SAS 9.2

h1

Deux exemples d’usage de la syntaxe de l’ODS : PROC PRINT et PROC REPORT

juin 26, 2011

Jusqu’à présent, j’ai présenté la syntaxe de l’ODS (Output Delivery System) de SAS avec la procédure PROC REPORT pour générer vos tableaux dans des fichiers .rtf (ODS RTF), .pdf (ODS PDF) ou en XML avec extension .xls (ODS TAGSETS.EXCELXP).

PROC PRINT se révèle dans les cas les plus simples aussi avantageux. Voici deux fichiers .pdf contenant la même table, une fois générée avec PROC REPORT et une fois avec PROC PRINT.

ods listing close;

*1. Exemple de l’ODS avec PROC REPORT;

ods pdf file=‘O:/sasref/exemple_report.pdf’;
proc report data=sashelp.class nowd;
columns sex age;
define sex / display style(column)=[cellwidth=2cm];
define age / display style(column)=[cellwidth=3cm];
run;
ods pdf close;

*2. Exemple de l’ODS avec PROC PRINT;

ods pdf file=‘O:/sasref/exemple_print.pdf’;
proc print data=sashelp.class nobs;
var sex / style(column)=[cellwidth=2cm];
var age / style(column)=[cellwidth=3cm];
run;
ods pdf close;

ods listing;

h1

Plusieurs formats pour une variable numériques – passer à une variable caractère avec la fonction PUTN

octobre 14, 2010

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

Dans cet article que vous propose une illustration de la fonction PUTN. En effet une variable numérique peut contenir des groupes de valeurs. Chaque groupe de valeurs se réfère à un format donnée. Le nom de ces formats est disponible dans une autre variable. La question est alors comment puis-je créer une variable caractère équivalent simplement, sans boucle, sans if-then, etc. La solution : la fonction PUTN. Voici un exemple pour illustrer le propos.

1. Le problème en exemple

Dans cet exemple, deux formats numériques AGE et SEX exitent.

proc format;
value age 11-13=’11-13′
14-16=’14-16′;
value sex 1=‘Male’
2=‘Female’;
run;

Dans un data set, ONE, trois variables existent :

  • CRITERIA : les critères sont AGE et SEX dans l’exemple.
  • CODLST : le nom des formats qui expliquent les valeurs numériques sont enregistrés dans la variable CODLST.
  • VALN: les valeurs numériques associées aux critères sont disponibles dans la variable VALN.

data one;
length criteria $8 codlst $8;
input criteria $ codlst $ valn;
age age 12
sex sex 1
;
run;

L’objectif est de créer une variable VALC qui contienne l’équivalent alphanumérique de VALN (la valeur donnée dans le label du format).

2. La solution proposée : PUTN

data two;
set one;
length valc $20;
VALC=putn(valn,codlst);
run;

3. Le résultat attendu

criteria codlst valn valc

age      age    12   11-13
sex      sex    1    Male

Ici les formats sont tous numériques. La fonction PUTN est utilisée.
Pour des formats alphanumériques, il faudra se servir de la fonction PUTC.

Allez plus loin

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

h1

Répéter la valeur d’une variable sur chaque page avec ODS RTF

septembre 26, 2010

Il y a un peu plus d’un mois, je vous parlais de l’option SPANROWS de PROC REPORT pour pouvoir répéter une valeur groupée sur chaque page du listing.

Mais si vous devez créer un fichier .RTF et non un fichier .PDF ou si vous n’avez pas SAS 9.2, vous pouvez vous rabattre sur cette solution.

Elle présente le seul inconvénient de séparer la table en table distincte à chaque nouvelle valeur du la variable groupée.

Voici donc un exemple à tester par vous même.

1. Le setting

Par simple soucis de présentation, quelques instructions de paramétrage sont données.

  • Enlever le titre par défaut avec l’instruction TITLE.
  • Enlever la date et le numéro de page par défaut et alignez le résultat à gauche.
  • Créer un format caractère SEX où M réfère à Garçon et F à Fille.


*——————————————–;
* Setting;
*——————————————–;

title;
options nodate nonumber nocenter;

proc format;
value $ sex ‘M’=‘Garçon’
‘F’=‘Fille’;
run;

2. Préparation des données

Afin d’avoir assez de données le fichier CLASS est multiplié par 5. Les noms sauvegardés dans la variable NAME sont incrémentés d’un nombre.

*——————————————–;
* 2. Data Preparation;
*——————————————–;

data class;
set sashelp.class;
output;
name=cats(name,’1′);
output;
name=cats(name,’2′);
output;
name=cats(name,’3′);
output;
name=cats(name,’4′);
output;
name=cats(name,’5′);
output;
run;

3. Reporting;

Vos données doivent être triées afin d’utiliser l’instruction BY dans PROC REPORT.

L’option d’ODS RTF STARTPAGE=NEVER empêchera le passage à une nouvelle feuille à chaque nouvelle valeur de la variable SEX.

Au moyen des options COMPUTE/ENDCOMP, il est possible de personnaliser le texte en début de chaque page. Un texte aligné à gauche est ajouté. Une ligne avant et une ligne après sont ajoutées pour faciliter la lisibilité du rapport. Ce texte est composé de « SEXE :  » suivi de la valeur formatée de la variable SEX.

*——————————————–;
* 3. Reporting;
*——————————————–;

proc sort data=class;
by sex;
run;

*options nobyline;

ods rtf file=’C:/…/test1.rtf’ startpage=never;
proc report data=class;
by sex;
column sex name;
define sex  / /*id*/ group noprint ;
define name / display  ‘Nom’;

compute before _page_ /style=[just=left] ;
line ‘ ‘;
line @1 ‘Sexe:’ @6 sex $sex. ;
line ‘ ‘;
endcomp;

run;

ods rtf close;

h1

Avec ODS, comment ajouter des caractères spéciaux ≤ et ≥

septembre 19, 2010

Comment inclure dans un rapport généré par ODS les symboles ≤ et ≥ ? En effet, ils ne font pas parti des caractères spéciaux ASCII classiques, il s’agit de caractères dépendants d’une police de caractères en particulier : la police « symbol ».

SAS propose un article sur le sujet. Je vous propose de détailler l’exemple utilisé qui a été utilisé avec SAS 8.2 sous environnement DBCS.

1. Setting

Dans cette instruction ODS ESCAPECHAR, est précisé que l’accent circonflexe sera utilisé, non pas comme simple caractère, mais comme caractère introduisant une notation particulière pour le style.

ods escapechar= »^ »;

Un format appelé TEMP est créé. La valeur 11 aura un label composé du symbole « inférieur ou égal ».

  • Le symbole « inférieur ou égal » en lui même est introduit par le code hexadécimal A3.
  • Pour que ce que code corresponde à « inférieur ou égal », il faut utiliser la police de caractère, d’où le code font_face=symbol.
  • Avant A3, on change le style et en particulier la police de caractère. Notez ici l’accent circonflexe introduit précédemment pour entrer la police.
  • Après A3, on arrête d’utiliser cette police.

proc format;
value temp 11=‘The value is ^S={font_face=symbol}’ « A3″x ‘^S={} the value’;
run;

2. Reporting

A présent SAS va écrire tout ce qui suite dans un fichier temp.rtf. Vous avez ici seulement besoin de préciser le chemin d’accès au fichier dans les guillemets.

Le résultat s’affichera correctement dans votre fichier .RTF mais pas dans votre sortie listing classique. Autant fermer cette destination avec ODS LISTING CLOSE.

ods listing close;

ods rtf file=‘temp.rtf’;

Les deux tableaux imprimé se basent sur la table CLASS dans la bibliothèque SASHELP.

Dans le premier cas, le format créé précédemment est appliqué à la variable AGE. On aura dont le label de format défini précédemment quand AGE=11.

title ‘This uses the special characters in the value’;
proc print data=sashelp.class;
format age temp.;
run;

Dans ce second exemple, le symbole « supérieur ou égal » est introduit avec le code hexadécimal B3 d’où « B3″x.

Comme précédemment, il est entouré de ^S={font_face=symbol} avant et ^S={} après.

Cette fois ci pas contre le symbole est ajouté dans le label d’une variable. Chacun des groupes de mot est donc mis entre guillemets.

title ‘This uses the special characters in the label’;
proc print data=sashelp.class label;
label age=« Age » « ^S={font_face=symbol} » « B3″x « ^S={} » « 10 »;
run;

Enfin, on précise de former le fichier .rtf et donc de ne plus ajouter d’info dedans à partir de maintenant.

ods rtf close;

ods listing;

Source : Usage Note 24054: In ODS, how can I add special characters such as GE or LE to my output?

Lecture complémentaire

h1

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

septembre 12, 2010

Vous savez comment lire un fichier .txt avec SAS mais avez-vous déjà envisager lire votre programme ou encore votre log et d’en faire un data set pour pouvoir fouiner un peu dedans ? Voici donc un exemple très basique côté programmation mais qui peut se révéler très utilise si vous faites preuve d’un peu d’imagination.

1. Commentaires sur l’exemple

Dans l’exemple qui suite la log sauvegardée de manière permanente sur le disque dur est importée dans SAS. Une ligne est égale à une observation. Le délimiteur est le caractère hexadécimal 09. Le nombre maximum de caractères par observation est ici de 1000. A vous de trouver la valeur qui vous semble la mieux appropriée pour éviter que le texte soit coupé sans pour autant sur-consommer votre capacité de stockage.

2. L’exemple

data mylog;
infile ‘c:/sasref/test.log’ dlm=’09’x;
length x $1000;
input x $;
run;

3. Aller plus loin

Ensuite pour vous entraîner, sortez les lignes où il y a le mot NOTE, les lignes avec le mot REAL TIME ou encore les lignes contenant un mot-clé qui vous est propre à l’aide de fonctions caractères.

Dans ce dernier cas, vous pouvez inclure dans votre programme les titres des grandes rubriques de votre programme et ensuite les extraire avec cette méthode. Pratique pour retrouver rapidement la structure d’ensemble de son programme, mettre à jour son en-tête, etc.

Lectures complémentaires

h1

Une option SAS 9.2 pour ODS PDF : répéter une valeur groupée sur plusieurs pages

août 3, 2010

Lorsque vous construisez un listing avec ODS PDF et PROC REPORT l’option GROUP de l’instruction DEFINE sert à n’afficher chaque valeur de la variable concernée qu’une seule fois.

Hors, si cette valeur s’applique aux observations de plusieurs pages, elle ne sera pas répétée à moins d’ajouter l’option SPANROWS nouvelle avec SAS 9.2.

Cette options ne fonctionne pas actuellement avec ODS RTF.

Voici un exemple pour tester par vous même.

1. Le setting

Par simple soucis de présentation, quelques instructions de paramétrage sont données.

  • Enlever le titre par défaut avec l’instruction TITLE.
  • Enlever la date et le numéro de page par défaut et alignez le résultat à gauche.
  • Créer un format caractère SEX où M réfère à Garçon et F à Fille.


*——————————————–;
* Setting;
*——————————————–;

title;
options nodate nonumber nocenter;

proc format;
value $ sex ‘M’=‘Garçon’
‘F’=‘Fille’;
run;

2. Préparation des données

Afin d’avoir assez de données le fichier CLASS est multiplié par 5. Les noms sauvegardés dans la variable NAME sont incrémentés d’un nombre.

*——————————————–;
* 2. Data Preparation;
*——————————————–;

data class;
set sashelp.class;
output;
name=cats(name,’1′);
output;
name=cats(name,’2′);
output;
name=cats(name,’3′);
output;
name=cats(name,’4′);
output;
name=cats(name,’5′);
output;
run;

3. Reporting

Enfin la section qui nous intéresse vraiment : générer un fichier .RTF et un fichier .PDF avec l’option SPANROWS et voir que que seul ODS RTF tient compte de cette option pour répéter l’observation en début de chaque nouvelle page.


*——————————————–;
* 3. Reporting;
*——————————————–;

ods listing close;
ods rtf file=‘C:\sasref\test1.rtf’;
ods pdf file=‘C:\sasref\test1.pdf’;


proc report data=class spanrows nowd;
column sex name;
define sex / group ‘Sexe’;
define name / display ‘Nom’ ;
run;


ods pdf close;
ods rtf close;
ods listing;

h1

Entrer une date avec l’informat ANYDTDTE

juin 6, 2010

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

Aujourd’hui j’aimerais vous présenter un informat destiné aux dates qui est apparu avec la version 9 de SAS : ANYDTDTE.

La manière dont est écrite une date est très variable et le nombre d’informat pour pourvoir entrer ces dates dans une table SAS est aussi large que le nombre de manière d’écrire une date. Du coup, difficile de se souvenir du nom de chacun des informats lorsqu’on rencontre une structure différente de son habitude de manière occasionnelle. Le passage par la documentation de SAS est quasiment obligé.

L’informat ANYDTDTE regroupe plusieurs informats sous sa coupole pour vous faciliter ce travail de mémorisation. Illustration.

1. Présentation de trois informats : DATE9., DDMMYY10. et ANYDTDTE.

De manière classique un informat reconnait une structure particulière.

  • L’informat DATE9 reconnait une date écrite sous la forme DDMMMYYYY (15APR2007).
  • L’informat DDMMYY10. reconnait les dates de la forme DD/MM/YYYY (15/04/2007).

L’informat ANYDTDTE vous permettra de retrouver les deux structures et plus encore.

2. Un exemple

Dans cet exemple la date est écrite de deux manières différentes. Deux choix s’offrent à vous :

  • informat date1 ddmmyy10. date2 date9.;
  • informat date1 date2 anydtdte.;

Dans le premier cas, vous identifiez de manière précise la structure de chacune des dates et appliquez l’informat de votre choix.

Dans le second cas, vous laissez SAS identifiez la structure des deux dates parmi une liste de 8 informats : DATE, DATETIME, DDMMYY, JULIAN, MMDDYY, MONYY, TIME, YYMMDD ou YYQ.

data event;
informat date1 date2 anydtdte.;
*informat date1 ddmmyy10. date2 date9.;
format date1 date2 date9.;
input event date1 date2;
datalines;
1 15/04/2007 15APR2007
1 20/10/2007 20OCT2007
3 11/02/2007 11FEB2007
4 14/11/2007 14NOV2007
8 15/02/2007 15FEB2007
9 28/01/2007 28JAN2007
17 15/01/2007 15JAN2007
17 30/04/2007 30APR2007
19 12/08/2007 12AUG2007
19 25/08/2007 25AUG2007
20 21/02/2007 21FEB2007
;
run;

proc print data=event;
run;

Lecture complémentaire

Lecture complémentaire sur la documentation en ligne de SAS

SAS Online Doc >Base SAS > SAS Language Reference : Dictionary > Dictionary of Language Elements > Informats

  • ANYDTDTEw. Informat
  • DDMMYYw. Informat
  • DATEw. Informat

Aller plus loin

Découvrez le cours de novembre 2022 : Les fonctions put et input – un sujet épineux

h1

Mettre des données côte-à-côte pour votre reporting

mai 24, 2010

Lorsque vous devez présenter vos données (faire du reporting), vous pouvez vous trouver dans la situation suivante : mettre côte-à-côte des données qui n’ont rien à voir entre elles. La situation peut se résoudre très rapidement avec un merge sans instruction BY. Mais que faire dans le cas où vous devez quand même grouper vos données par une clé (exemple l’identifiant du client) mais dans chaque source plus d’une observation par clé ? C’est ce que je vous propose de découvrir dans cet article.

1. Les données pour l’exemple

Deborah a deux lignes d’observation et Patrick aussi.

data demography;
length cl_name $10 criteria $10 ;
input cl_name $ criteria $ crit_value ;
datalines;
deborah age 15
deborah height 1.66
patrick age 14
patrick height 1.75
;
run;

Deborah a acheté 4 articles (DVD, téléphone portable, une radio et des écouteurs (4 lignes d’observations pour Deborah) tandis que Patrick a acheté deux articles.

data sell;
length cl_name $10 achat $10;
input cl_name $ achat $;
datalines;
deborah dvd
deborah mobile
deborah radio
deborah headset
patrick mobile
patrick tv
;
run;

2. Le résultat sans instruction BY

data mix_demo_sell;
merge demography
sell;
by cl_name;
run;

Vous vous retrouvez avec un merge MANY-to-MANY qui ne résous par votre problème. Pensez toujours à vérifer votre log après un MERGE. Ce type de note est souvent signe d’une erreur de raisonnement dans votre programme.

proc print data=mix_demo_sell;
run;

On observe ici un RETAIN implicite propre au merge.

3. Ajouter un compteur pour chaque client

Pour contourner le problème, on ajouter un identifiant supplémentaire dans les deux tables.

Dans la table DEMOGRAPHY, le client DEBORAH a deux observations. On aura donc CNT=1 et CNT=2.

data demography;
set demography;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;

Dans la table SELL, le client DEBORAH a quatre observations. On aura donc CNT=1, CNT=2, CNT=3 et CNT=4.

data sell;
set sell;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;

Il ne reste plus qu’à combiner les deux tables à partir de la variable client (CL_NAME) et de la variable CNT.

data mix_demo_sell;
merge demography
sell;
by cl_name cnt;
run;

proc print data=mix_demo_sell;
run;

Le résultat désiré se présente ainsi :

Lecture complémentaire

h1

Une petite histoire de macro : compter le nombre de mots dans un paramètre de macro

avril 11, 2010

Il est courant de devoir compter le nombre de mots dans un paramètre de macro. Il est par exemple possible de vouloir créer une boucle pour travailler chacun des termes contenu dans cette macro de manière séparée.

Voici donc l’histoire d’une mini macro qu’on nommera CNT_WRD qui crée une macro variable TOT_WRD renvoyant le nombre de mots contenu dans le paramètre TXT.

Ceci est pour vous l’occasion de voir ou revoir un raisonnement possible dans la construction d’une macro sous SAS.

1. Préciser ses besoins, une rapide « spécification »

La macro CNT_WRD composée d’un seul paramètre retournera dans une macro variable TOT_WRD le nombre de mots contenus dans le texte donné dans le paramètre de macro.

Ici on considérera comme mot, tout terme séparé par au moins un blanc.

Si le paramètre de macro est vide, la macro ne devra pas afficher de message d’erreur et la macro variable TOT_WRD sera égale à 1. Par défaut, aucune valeur ne sera entrée dans le paramètre TXT.

La macro variable doit pouvoir être utilisable à l’extérieur de la macro (macro variable globale).

2. Tester la fonction COUNT dans une étape data

La fonction COUNT permet de comptabiliser certains caractères et donc de répondre à ce type de besoin. En fait, cette fonction ne compte pas le nombre de mots mais compte le nombre de caractères définis par le second élément dans la fonction; dans notre cas, elle comptera le nombre de blancs. Il faut donc ajouter 1 au total.

Voici un exemple dans une étape data.

data _null_;
tot_wrd=1+count(‘mot1 mot2’,‘ ‘);
put tot_wrd=;
run;

Dans la log, vous pouvez voir que cnt_wrd=2.

Mais cela ne suffit pas pour gérer les blancs multiples et les blancs aux extrémités. Car si vous avez plus d’un blanc entre chaque mot, chacun sera compté. Il faut donc les enlever au préalable (avec la fonction COMPBL ici). Les blancs de début et fin peuvent s’enlever au moyen de la fonction STRIP.

data _null_;
tot_wrd=1+count(strip(compbl(‘ mot1 mot2 ‘)),‘ ‘);
put tot_wrd=;
run;

Mais que ce passe t-il si notre texte à compter est vide ? TOT_WRD sera égal à 1. Il faut donc ajouter le 1 au total que si le texte à analyser n’est pas vide.

data _null_;
length txt $200;
txt=;
if txt ne ‘ ‘ then tot_wrd=1+count(strip(compbl(txt)),‘ ‘);
put tot_wrd=;
run;

3. Créer la macro

Comme indiqué dans le dernier point, on travaille ici de manière conditionnelle. Si le paramètre de macro TXT est vide, la macro variable CNT_WRD nouvellement créée prend la valeur zéro. Sinon, On passe par la fonction COUNT.

Comme il n’existe pas d’équivalent aux fonctions COUNT et COMPBL en langage macro, il faut encadrer chacune d’elle dans une fonction macro SYSFUNC.

Ici on notera que la fonction STRIP n’apparaît pas. Les blancs de début et de fin en langage macro n’ont aucun impact.

%macro cnt_wrd(txt=);

%global tot_word;

%if &txt.= %then %let tot_wrd=0;
%else %let tot_wrd=%eval(1+%sysfunc(count(%sysfunc(compbl(&txt.)),%str( ))));

%mend cnt_wrd;

Pour représenter un blanc dans une étape data, il suffit d’utiliser des guillemets. En langage macro, on fait appel à la fonction %STR(). Il faudra ne pas oublier d’ajouter un blanc entre les parenthèses.

Afin d’ajouter 1 au résultat de la fonction COUNT, il faut utiliser la macro fonction %EVAL. Le contenu des macro variables sont sinon tous interprétés comme du texte, qu’il s’agisse de nombres ou pas.

Enfin, pour que cette macro variable TOT_WRD soit utilisable en dehors de la macro, il faut qu’elle soit globale. Hors par défaut, une macro variable créée dans une macro est locale, c’est-à-dire n’existe que le temps de la macro. L’instruction %GLOBAL TOT_WRD; résouds le problème.

4. Tester la macro dans le cadre de sa validation

Que se passe t-il quand on ne change pas la valeur par défaut du paramètre de macro ?

%cnt_wrd;
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il quand le paramètre de macro TXT est vide de texte ?
%put Valeur de TOT_WRD: &tot_wrd;

%cnt_wrd(txt=);
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il lorsqu’il n’y a qu’un mot?

%cnt_wrd(txt=mot1);
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il quand il y a plusieurs mots ?

%cnt_wrd(txt=mot1 mot2 mot3);
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il quand il y a des blancs multiples entre les mots, en début et à la fin ?

%cnt_wrd(txt= mot1 mot2 mot3 );
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il quand il y a des blancs multiples entre les mots, en début et à la fin ?

%cnt_wrd(txt=mot1 mot2);
%put Valeur de TOT_WRD: &tot_wrd;

Que se passe t-il quand la macro est appelée plusieurs fois ?

%cnt_wrd(txt=mot1 mot2);
%put Valeur de TOT_WRD: &tot_wrd;
%cnt_wrd(txt=mot1);
%put Valeur de TOT_WRD: &tot_wrd;

Lecture complémentaire

h1

Une fonction LIBREF au résultat inattendu

mars 23, 2010

La fonction LIBREF vérifie l’existence d’une bibliothèque. Vu que la réponse attentue est oui ou non, on pourrait s’attendre à une résultat binaire avec zéro pour non et un pour oui. Dans les faits, cette fonction retourne zéro pour oui et toute autre valeur signifie non.

Voici un exemple.

1.  Contexte, exemple

Vous cherchez à savoir si le chemin d’accès défini dans un  paramètre de macro peut servir de bibliothèque. Une solution est de tenter de créer la bibliothèque et ensuite de vérifier si la bibliothèque a été créée ou non.

2. Le programme

Dans l’exemple qui suit, une macro TEST est créée. Elle a un paramètre DSNPATH=. Le chemin d’accès donné dans ce paramètre est utilisé pour créé la bibliothèque INLIB.

Ensuite pour les besoins de l’exemple, un message est ajouté dans la log au moyen des instructions %PUT.

  • Tout d’abord, est indiqué dans la log la valeur prise par le paramètre de macro DSNPATH.
  • Puis, la valeur prise par la fonction LIBREF est affiché dans la log.

Afin de pouvoir utiliser cette fonction hors d’une étape data ou d’une procédure PROC SQL, il faut l’englober dans une macro fonction %SYSFUNC().

En fin de macro la référence à la bibliothèque est supprimée.

%macro test(dsnpath=);
libname inlib « &dsnpath. »;
%put MESSAGE: DSNPATH= &dsnpath.;
%put MESSAGE: Voir le résultat de la fonction LIBREF dans la log: %sysfunc(libref(inlib));
libname inlib;
%mend test;

Le premier appel de macro se fait avec un chemin d’accès valid. Tandis que le second appel de macro utilise un chemin d’accès erroné.

%test (dsnpath=C:/sasref);
%test (dsnpath=C:/sasre);

3. La log

Lorsque le chemin d’accès est correct, la fonction LIBREF retourne la valeur 0.

Quand le chemin d’accès n’est pas correct, la fonction LIBREF retourne une valeur différente de zéro. Dans l’exemple, il s’agit de la valeur -70008.

Lectures complémentaires

Autres articles sur %SYSFUNC

SAS Online Doc

  • Summary Descriptions and Syntax
  • LIBREF Function
h1

Passer d’un format A4 à un format LETTRE

mars 1, 2010

Vous voulez imprimer les fichiers RTF générés avec ODS RTF dans une autre forme que le format A4. Quelle option utiliser pour utiliser un autre format standard comme le format LETTRE ? Comment personnaliser la zone d’impression et gérer les marges en conséquences ?

1. Par défaut, le papier est au format A4 (21cm/29,7cm)

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

2. Changer la taille du papier pour l’impression pour une lettre (21,59cm/27,94cm)

options papersize=letter;

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

3. Personnaliser la taille (21cm/27,94cm)

Afin de personnaliser les marges dans l’instruction globale OPTIONS, je choisi ici d’enlever toute valeur au niveau du template (undefine margin). Ensuite ce template TEST_PAPERSIZE est appelé dans l’instruction ODS RTF.

proc template;
Define Style style.test_papersize;
parent=styles.rtf;
style Body from Body /
leftmargin=_undef_
right margin=_undef_
topmargin=_undef_
bottommargin=_undef_;
End;
run;

De la taille du papier, il faut enlever les marges. Ici, nous voulons un papier avec une largeur de 21cm et une hauteur de 27,94cm. Les marges étant de 2 centimètres de chaque côté, on enlève 4 cm à la hauteur et 4 cm à la largeur définie par l’option PAPERSIZE.

Les paramètres de l’option PAPERSIZE :

  1. Le 1er paramètre : la largeur
  2. Le 2ème paramètre : la hauteur

options papersize=(’17cm’,‘23.94cm’) leftmargin=2cm rightmargin=2cm topmargin=2cm bottommargin=2cm;

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

Note : j’ai obtenu le résultat escompté avec Word 2003 mais pas avec Word 2007. Vous pouvez apporter un commentaire avec votre expérience sur le sujet.

h1

20 pistes pour vérifier le contenu d’un data set

février 16, 2010

AA : Faites des vérifications sur ces données.

BB: Vous avez un descriptif des choses que vous voulez voir vérifier ? AA : Non.

BB: J’imagine donc que vous ne savez pas quelles sont les vérifications les plus importantes ? AA : Oui c’est bien cela.

BB: Vous savez sous quelle forme vous voulez avoir l’information ? BB: Lisible.

Voici quelques pistes pour aborder ce genre de travail.

1. Travailler au niveau de la cellule

Pour chaque variable, listez les valeurs possibles.

  1. la variable A peut ne prendre que les valeurs N ou Y, ne peut prendre que des valeurs manquantes ? (valeurs discrètes).
  2. Dans quel intervalle les valeur sont-elles autorisées ? (valeurs continues).
  3. Les valeurs manquantes sont-elles autorisées ? Si oui, lesquelles pour les variables numériques : le point, .A, ._, etc. ?
  4. Les valeurs numériques doivent-elles être arrondies ?
  5. La case des variables caractères est importante ? Tout doit-il être en majuscule ?
  6. Les blancs de début, de fin ou les blancs multiples sont-ils autorisés ?
  7. Est-ce que plus d’un seul mot est autorisé ?
  8. Est-ce que les caractères spéciaux sont autorisés et si oui lesquels ? Seulement les caractères imprimables ?

2. Le cas particulier des dates

  1. Pour les variables jour, mois et années, clarifiez si la date doit être complète ou non ?
  2. Si une date incomplète est autorisée, parle t-on d’une date où seul le jour peut-être manquant, où le jour et le mois peuvent être manquants, où le jour, le mois et l’année peuvent être manquants ?
  3. Comment gère t-on les dates dans le futur ? Utilise-t-on le moment d’exécution du programme comme date séparant le passé du futur ?  Si le jour et le mois sont manquants, dit-on que l’année en cours est une valeur valide ? Ainsi, si l’année 2011 est entrée, quel est le résultat si le programme est exécuté le 31 décembre 2010 et le 1er janvier 2011 ?
  4. Comment comparer deux dates autorisant des valeurs manquantes ?

3. Travailler avec plusieurs lignes et/ou colonnes

Après avoir vérifier les valeur valables au niveau de la cellule, il s’agit de faire des comparaisons horizontales et verticales, sur toute une ligne, toute une colonne ou seulement certaines variables d’une ligne ou certaines variables d’une colonne. Voir plusieurs lignes et plusieurs colonnes.

  1. Il vous faudra clarifier si les doublons dans une variable sont autorisés.
  2. Pensez à inverser la requête. Par exemple, si les valeurs de ma variable CRITERIA finissent pas OLD alors je parle d’anciens critères. Ma requête vérifiera que lorsque CRITERIA=xxOLD alors FLAG=OLD d’une part et que lorsque FLAG=OLD, CRITERIA=xxOLD : if not (substr(criteria,length(criteria)-2)=’OLD’ and flag=’OLD’);
  3. La plus grande difficulté consistera à éviter d’avoir plusieurs requêtes pour une seule valeur erronée. Par exemple, vous avez trois variables oui/non: AA, BB et CC. La première requête vérifera que AA=Y ou AA=N, que BB=Y ou BB=N et que CC=Y ou CC=N. Ensuite, si AA=Y alors REFEREFENCE ne doit pas être manquant. Il est important ici de ne pas avoir une requête supplémentaire si déjà AA  a des valeurs non autorisés identifiées précédemment.

4. Documenter les requêtes dans un tableau

  1. Vous aurez souvent intérêt à lister toutes vos requêtes dans une table. Que vous lirez par la suite.
  2. Il peut être intéressant d’identifier chaque requête par un nom plutôt qu’un numéro cas très probable où de nouvelles requêtes doivent s’insérer entre des requêtes déjà existantes. Vous pouvez ensuite insérer un numéro pour le tri uniquement.
  3. Une autre table peut servir à lister les exceptions à la règle.

5. Présenter les résultats dans un tableau

Enfin, la présentation sous forme de tableau s’avèrera plus lisible qu’un fichier .rtf, .pdf.

  1. D’une part le volume est moindre avec un tableau qu’avec un fichier textuel. Cela décourage moins les personnes qui doivent le lire.
  2. D’autre part, sous Excel, les utilisateurs apprécieront les filtres et la possibilité de trier les données.

Vous pouvez étendre cette réflexion au cas où vous devez vérifier plusieurs tableaux. Quelles sont les variables communes aux différentes sources. Dans quelle mesure doivent-elles être compatibles ? Est-il préférable de tout programmer dans un seul programme ou d’appeler un programme par requête ? Il faudra

h1

Les expressions régulières, un exemple avec des crochets à remplacer

février 8, 2010

Les expressions régulières donnent à SAS plus de flexibilité dans le travail des chaînes de caractères que les fonctions classique comme INDEX, TRANWRD, SUBSTR ou encore SCAN. Voici un exemple de code remplaçant le contenu dans des crochets.

1. Le data set qui sert d’exemple

A la base on a un fichier TEXT avec une ligne d’observation et une variable TEXT de longueur 50.

TEXT est égal à : ab CD ef [gh] [] [kl] mn [op].

data text;
length text $50;
text=‘ab CD ef [gh] [] [kl] mn [op]’;
run;

2. L’étape data est divisée en trois parties

On veut ici remplacer le contenu entre crochets par un seul et unique x.

data text (drop=rx:);
set text end=eof;

*1. Créer RX1;
retain rx1 0;
if _N_=1 then rx1=rxparse(« ‘[‘ ^'[]’ *’]’ to ‘[x]' »);

*2. Créer NEW_TEXT;
length new_text $50;
call rxchange (rx1,99999, text, new_text);

*3. Supprimer RX1;
if eof then call rxfree(rx1);

run;

Voici le résultat attendu :


3. La premier partie du programme, création de la variable RX1

Extrait du code :

*1. Créer RX1;
retain rx1 0;
if _N_=1 then rx1=rxparse(« ‘[‘ ^'[]’ *’]’ to ‘[x]' »);

Dans un premier temps la variable RX1 est créée au moyen de la fonction RXPARSE qui ne contient qu’un paramètre dont les valeurs sont entre guillemets, ici des guillemets doubles. Il s’agit de remplacer une chaîne de caractères

  • qui commence par un crochet ouvrant: ‘[‘
  • qui termine par un crochet fermant : ‘*]’
  • qui ne contient pas à l’intérieur d’autres paires de crochets : ^'[]’

par

  • un x entre crochet : to ‘[x]’

L’opération étant identique pour toutes les observations du data set, il suffit de l’effectuer l’opération quand _N_=1 et d’étendre le résultat à toutes les observations avec un RETAIN rx1 0;. Cela s’avère très bénéfique pour les grandes data sets en terme de performance du programme.

4. La seconde partie du programme, création de la variable NEW_TEXT

Extrait du code :

*2. Créer NEW_TEXT;
length new_text $50;
call rxchange (rx1,99999, text, new_text);

Une nouvelle variable NEW_TEXT de longueur 50 est créée. La fonction CALL RXCHANGE qui sert à la définir est composée de 4 paramètres.

  1. Tout d’abord RX1 qui donne la chaîne de caractère d’origine et celle par laquelle elle doit être remplacée.
  2. Ensuite 99999 est un large nombre qui précise le nombre maximum de changements qui peuvent être fait.
  3. TEXT est la variable d’origine
  4. NEW_TEXT est le nom de la nouvelle variable.

Notez que pour changer la variable existante plutôt que de créer une nouvelle variable, il vous suffit de limiter la fonction aux trois premiers paramètres.

call rxchange (rx1,99999, text);

5. La troisième et dernière partie, suppression de la variable RX1

Extrait du code :

*3. Supprimer RX1;
if eof then call rxfree(rx1);

Afin de libérer de l’espace en arrière plan, la fonction CALL RXFREE est appelée en fin de programme pour supprimer RX1 en tant qu’indicateur d’expression régulière.

Lecture complémentaire :
Some Practical Ways to Use the New SAS Pattern-Matching Functions, Mike Rhoads, Westat, Rockville, MD (SAS version 6.11 et SAS 6.09 Experimental)

h1

L’option NOTSORTED de l’instruction BY : A quoi cela sert-il ?

janvier 24, 2010

Dans une instruction BY, l’option NOTSORTED fait parfois son apparition.

Le résultat de cette option diffère de celui avec un tri préalable.

Voici l’illustration de cette option dans un PROC TRANSPOSE.

1. Les données : SASHELP.CLASS

Le dataset SASHELP.CLASS et plus particulièrement ses variables AGE et WEIGHT servent pour l’exemple.

2. Un usage classique de l’instruction BY

De manière générale, pour utiliser une instruction BY,
il faut que les observations soient triées de la même maniÈre dans le fichier d’entrée.

Ici les données sont triées par AGE.

Comme on ne peut pas modifier les fichiers de la bibliothèque SASHELP,
le résultat après le tri est sauvegardé dans la bibliothèque temporaire WORK.

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

Puis la mesure de poids (WEIGHT) est transposée.

proc transpose data=class out=class;
var weight;
by age;
run;

On se retrouve donc avec une ligne par AGE.

2. L’option NOTSORTED

L’option NOTSORTED se place en fin d’instruction BY.

proc transpose data=sashelp.class out=class;
var weight;
by age notsorted;
run;

Cette fois-ci à chaque changement d’âge dans le fichier d’origine, une nouvelle ligne est ajoutée dans le fichier de sortie.

Par exemple l’âge des observations 2 et 3 du fichier d’origine se suivent : 13.
Dans le fichier final, une seule ligne sera formée à partir de ces deux fichiers. Le premier poids 84 ira dans la variable COL1 et le second 98 dans la variable COL2.

Le même principe s’applique deux autres fois: observations 4 et 5 avec âge=14, observations 6 et 7 avec âge=12.

Lectures complémentaires

h1

Créer un libname à partir d’un autre libname

janvier 18, 2010

De manière occasionnelle, il est pratique de définir une nouvelle bibliothèque SAS à partir d’une autre bibliothèque plutôt qu’en redonnant le chemin d’accès à la bibliothèque. Voici un exemple de cette syntaxe. Simple et efficace.

Un cours exemple

Dans un premier temps, la bibliothèque PROJECT est créée. Elle désigne le répertoire C:/sasref.

libname project ‘C:/sasref’;

Dans un second temps, la bibliothèque MAIN est créée. Entre parenthèses est précisée qu’il faut utiliser comme répertoire celui de la bibliothèque PROJECT.

libname main (project);

Lectures complémentaires

h1

Sauvegarder le résultat d’une comparaison de deux data sets dans un data set avec PROC COMPARE

janvier 7, 2010

Fréquemment, le programmeur est amené à comparer deux datasets. Deux méthodes s’offrent à lui : un merge accompagné de l’option IN ou la procédure PROC COMPARE. Voici une illustration de PROC COMPARE.

1. Préparer les données

Pour illustrer la procédure PROC COMPARE, il nous faut deux data sets. Le premier s’intitule CLASS et est sauvegardé dans la bibliothèque SASHELP (SASHELP.CLASS). Le second s’appelle également CLASS. C’est un dérivé du premier. Il est savegardé dans la bibliothèque temporarire WORK (WORK.CLASS).

Voici comment est créé le second data set à partir du premier :

  • Une observation de la variable NAME passe de Alice à Alica
  • Une observation de la variable AGE prend la valeur 16 quand le nom est Robert
  • Une observation est ajoutée. La variable NAME prend la valeur Extra. Les autres variables ont des valeurs manquantes.

data class;
set sashelp.class;
if name=‘Alice’ then name=‘Alica’;
if name=‘Robert’ then age=16;
output;
if _N_=1 then
do
;
name=‘Extra’;
output;
end;
run;

2. L’importance d’avoir des données triées

Dans la procédure PROC COMPARE utiliser par la suite, j’ai choisi d’utiliser l’instruction ID. Cette instruction requiert que les données soient triées préalablement. En effet, si ce n’est pas le cas un message d’erreur comme celui-ci apparaît :

proc sort data=class;
by name;
run;

3. Enregistrer le résultat de la différence dans un data set

Ce qui m’intéresse ici est de sauvegarder le résultat de la comparaison dans un data set et non de l’afficher dans la sortie .txt. Pour ce faire, l’option OUT= précise le nom du data set qui sauvergardera les résultat et l’option NOPRINT stoppe l’affichage des résultats dans la log.

Quatres options précisent le contenu du résultat :

  • OUTNOEQUAL : seules les observations où une différence est détectée seront sauvegardés
  • OUTBASE : une ligne contiendra les lignes d’observation du fichier de base défini dans l’option DATA=
  • OUTCOMP : une ligne contiendra les lignes d’observation du fichier de comparaison indiqué avec l’option COMPARE=
  • OUTDIF: une ligne annotera les valeurs présentant des différences

En outre, l’instruction ID me permet de lister ma/mes variables que je considère comme des variables clés et d’en tenir compte dans la comparaison. J’ai choisi de comparer les observations seulement si elles ont la même valeur dans la variable NAME. Si une valeur de NAME n’est présente que dans un des deux fichiers, cette inconsistence sera également enregistrée.

proc compare data=sashelp.class compare=class
out=diff_class outnoequal outbase outcomp outdif
noprint;
id name;
run;

4. A quoi ressemble le fichier contenant les différences

Voici le contenu du fichier DIFF_CLASS répertoriant les les différences entre le fichier SASHELP.CLASS et le fichier WORK.CLASS.

options ls=max nocenter;
proc print data=diff_class width=min;
format _all_;
run;

Deux points sont à noter ici.

Tout d’abord, on a trois cas où la valeur de la variable définie dans ID est présente dans un seul des deux fichiers. Dans chacun de ces trois cas, le fichier DIFF_CLASS enregistre une seule ligne d’observations.

  • NAME=Alica est seulement présent dans le fichier de comparaison (WORK.CLASS)
  • NAME=Alice est seulement présent dans le fichier de base (SASHELP.CLASS)
  • COMPARE=Extra est seulement présent dans le fichier de comparaison (WORK.CLASS)

Puis, on a un cas où NAME=Robert est présent dans les deux fichiers mais avec des différences dans les autres variables. Une troisième ligne DIF précise où les différences et les égalités se situent.

  • Valeurs numériques
    • E pour égalités : c’est le cas des variables HEIGHT et WEIGHT
    • un nombre qui mesure la différence :  l’âge dans WORK.CLASS et de 4 plus grand que celui dans le fichier de base SASHELP.CLASS
  • Valeurs caractères
    • Un point pour des égalités : la variable SEX
    • Des xxx pour une différence : le cas ne se présente pas dans notre exemple

5. Un fichier est créé même si aucune différence n’est enregistrée

Il n’existe pas d’options dans PROC COMPARE pour ne créer un fichier que si au moins une différence entre les fichiers est trouvée.

proc compare data=sashelp.class compare=sashelp.class;
out=nodiff outnoequal outbase outcomp outdif
noprint;
id name;
run;

Vous devrez donc ensuite compléter votre programme à la suite de PROC COMPARE pour supprimer ces fichiers si c’est ce que vous avez besoin.

h1

Afficher toutes les valeurs possibles d’une variable définies dans un format avec PRELOADFMT option (PROC TABULATE)

décembre 2, 2009

Vous pouvez avoir besoin de réaliser un tableau comptant le nombre d’observations par catégories. Deux possibilités s’offrent à vous :
afficher le nombre d’observations parmi les catégories présentent dans vos données ou
afficher le nombre d’observations pour toutes les catégories possibles et imaginables définies dans un format. Les catégories non présentent dans les données ont alors une fréquence de zéro.

Par défaut, seules les catégories présentent dans les données seront retenues par PROC TABULATE.
Voici comment utiliser les options PRELOADFMT ORDER= et PRINTMISS pour prendre en compte tous les valeurs possibles et non seulement celles observées.

1. Préparer les données

Dans un premier temps, un format caractère $SEX est créé. Il prend trois valeurs possibles, M pour les hommes (male), F pour les femmes (female), et pour tout autre caractère, le label sera Missing.

proc format;
value $ sex ‘M’=‘Male’
‘F’=‘Female’
other=‘Missing’;
run;

2. Compter le nombre de garçons et de filles ayant une donnée pour l’âge.

Ici, on note que 10 garçons et 9 filles ont une donnée sur l’âge. Notez que la statistique n se limite aux valeurs non manquantes, sur le même principe que la fonction n. Si un âge est manquant, il ne sera pas inclus avec cette statistique mais avec la statistique nmiss.

proc tabulate data=sashelp.class;
class sex;
var age;
table sex=‘ ‘,age=‘ ‘*n=‘Freq’*f=5.;
format sex $sex.;
run;

A présent ce qui nous intéresse est d’afficher toutes les catégories possibles pour la variable SEX, comme définies dans le format $SEX.

Dans l’instruction CLASS, il faudra ajouter l’option /PRELOADFMT order=data.
Tandis que dans l’instruction TABLE, il faudra noter l’option PRINTMISS.

A la place de ORDER=DATA, vous pouvez mettre ORDER=FORMATTED, ORDER=UNFORMATTED ou encore ORDER=FREQ.

proc tabulate data=sashelp.class;
class sex/preloadfmt order=data;
var age;
table sex=‘ ‘,age=‘ ‘*n=‘Freq’*f=5./printmiss;
format sex $sex.;
run;

3. Calculer l’âge moyen des garçons et des filles

L’âge sera calculer en se servant des valeurs non manquantes.

L’âge moyen sera manquant (représenté par un point) pour les catégories de SEX où aucun âge n’est disponible. Vous pouvez remplacer ce point par un zéro via l’instruction TABLE au moyen de l’option /MISSTEXT=’0′.

Avant sans MISSTEXT=’0′

proc tabulate data=class;
class sex/preloadfmt order=data;
var age;
table sex=‘ ‘,age=‘ ‘*mean=‘Mean Age’*f=5./printmiss;
format sex $sex.;
run;

Après avec MISSTEXT=’0′

proc tabulate data=class;
class sex/preloadfmt order=data;
var age;
table sex=‘ ‘,age=‘ ‘*mean=‘Mean Age’*f=5./printmiss misstext=’0′;
format sex $sex.;
run;

h1

Ces caractères hexadécimaux non visibles au 1er coup d’oeil

novembre 23, 2009

Lors de l’importation de données d’un fichier Excel, il est fréquent d’importer au passage des caractères spéciaux non visible au premier coup d’œil. Par exemple, on peut trouver des blancs représentés en valeur hexadécimale par le code 20. Certains de ses caractères ressemblent à des blancs mais n’en sont pas. Ils ne disparaîtront donc pas avec une fonction COMPRESS sans troisième paramètre. La valeur hexadécimale de ces caractères est par contre une valeur lisible.

Voici comment afficher votre texte en valeur hexadécimale et ce dans la log ?

1. Illustration du problème

Dans cet exemple, une variable WEBISTE de longueur 25 est présente dans la table HEXFMT. Cette variable contient une observation http://www.sasreference.fr entourée d’un blanc avant et d’un blanc après. Cette valeur est créée ici au moyen de la fonction CAT.

Pour voir la différence entre la valeur de WEBSITE avec et sans un simple COMPRESS, une seconde variable EQUAL indique la valeur YES si les deux résultats sont identiques, NO sinon.

data hexfmt;
length website $25 equal $3;
website=cat(’20’x,‘www.sasreference.fr’,’20’x);
if website=compress(website) then equal=‘Yes’;
else equal=‘No’;
run;

proc print data=hexfmt;
run;

2. Voir les caractères hexadécimaux avec le format HEX

Ici, je vous propose de voir la valeur de la variable WEBSITE au moyen de l’instruction PUT. Il est possible de voir la valeur formatée plutôt que la valeur brute en faisant suivre la variable d’un format. Le format ici sera HEXw. où w est un nombre idéalement de la longueur de la variable fois deux. En effet, les caractères hexadécimaux sont toujours de longueur deux. Si votre texte est de longueur 25, il faudra 50 caractères pour l’afficher en valeur hexadécimale.

data hexfmt;
length website $25;
website=cat(’20’x,‘www.sasreference.fr’,’20’x);
put website= hex50.;
run;

proc print data=hexfmt;
run;

Dans le résultat qui suit, on voit donc le premier caractère de l’observation de WEBSITE a pour code 20. Le second caractère est la lettre W représentée par le code 77, et ainsi de suite.

Lecture complémentaire