Posts Tagged ‘sysfunc’

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

Protégé : Une fonction LIBREF au résultat inattendu

mars 23, 2010

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

h1

Récupérer la valeur d’une option système dans une macro variable, %SYSFUNC(GETOPTION())

avril 30, 2009

Les options SAS modifiables au moyen de l’instruction globale OPTIONS peuvent être retrouvées dans une étape data ou autre au moyen de %SYSFUNC(GETOPTION()).

Par exemple, cette semaine, j’ai eu besoin de savoir combien de caractères par ligne je pouvais entrer dans ma sortie (fenêtre OUTPUT). En d’autres termes, je voulais connaître la LINESIZE et en fonction d’elle ajuster les colonnes de mon listing généré au moyen d’un simple PROC REPORT.

1. Lire dans la LOG l’information

L’instruction PROC OPTIONS permet de lister toutes les options dans la fenêtre LOG de SAS. En ajoutant OPTION=, l’affichage est réduit à la seule option LINESIZE.

proc options option=linesize;
run;

Dans notre exemple, l’option LINESIZE est de 91. Jusqu’à 91 caractères pourront être affichés sur une même ligne avec un PROC PRINT ou autre.

LINESIZE=91 Line size for SAS log and SAS procedure output
NOTE: PROCEDURE OPTIONS used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds

2. Sauvegarder l’information dans une macro variable

Pour illustrer la syntaxe %SYSFUNC(GETOPTION()), je choisi de sauvegarder l’information dans une macro variable appelée CURRENT_LS. Cette valeur est ensuite affichée dans la LOG au moyen de l’instruction %PUT.

%let current_ls=%sysfunc(getoption(linesize));
%put &current_ls.;

Vous pouvez directement inclure %SYSFUNC(GETOPTION()), dans une instruction globale comme TITLE si vous le souhaitez.

La liste des options du système SAS est grande. A vous d’explorer les possibilités que vous offre cette notation.

h1

Evaluer le critère performance TEMPS d’un programme (%SYSFUNC, %SYSEVALF)

avril 10, 2009

Un critère pour évaluer la performance d’un programme est de connaître son temps d’exécution. La fonction système %SYSFUNC permettra de récupérer le temps à un instant donné et la fonction  %SYSEVALF servira à calculer la différence entre deux temps pré-enregistrés. Voici un exemple en 4 étapes.

1. Récupérer le temps en début de programme

Dans un premier temps, le temps de début est sauvegardé dans une macro variable TEMPS_DEBUT. Il est extrait au moyen de la fonction TIME() et est donc exprimé en secondes.

%let temps_debut = %sysfunc(time());

2. Exécuter la partie principale du programme

Pour l’exemple un simple PROC PRINT est ajouté comme partie principale du programme.

proc print data=sashelp.class;
run;

3. Récupérer le temps en fin de programme

Dans un troisième temps, le temps en fin de programme est sauvagardé dans la macro variable TEMPS_FIN. Comme précédemment; la fonction TIME() est utilisée.

%let temps_fin = %sysfunc(time());

4. Evalutation et affichage de la durée écoulée

La durée écoulé entre le début et la fin du programme est sauvegardée dans la macro variable DUREE. Cette durée est ensuite affichée dans la log au moyen de l’instruction %PUT.

Sur le même principe qu’une fonction %EVAL dans une macro, la fonction %SYSEVALF permet de considérer les deux variables TEMPS_DEBUT/TEMPS_FIN comme des nombres le temps du calcul de la différence.

%let duree = %sysevalf(&temps_fin.-&temps_debut.);
%put Durée d’exécution : &duree.;

Lectures complémentaires

www.sasreference.fr

SAS Online Doc

  • Using SAS Language Functions in the Data Step and Macro Facility
  • %SYSFUNC and %QSYSFUNC Functions
  • Summary Descriptions and Syntax
  • %EVAL Function
  • %SYSEVALF Function
  • How the macro processor evaluates Arithmetic Expressions
  • TIME Function
h1

Ajouter une date dans un nom de fichier Excel, Word…

mars 12, 2009

Sous SAS, en créant un fichier .xls ou .rtf avec la syntaxe de l’ODS (Output Delivery System), il est parfois pratique d’ajouter dans le nom du fichier une date. Par exemple : listing_20090311.xls.

Nous verrons ici plusieurs représentations de la date et de l’heure : afin d’avoir des noms triables par ordre chronologique, l’année apparaît avant le mois et le jour.

La syntaxe proposée, %SYSFUNC(fonction, format), s’utilise dans d’autres cas que la définition d’un nom de fichier (.rtf, .xls, …). De manière générale, elle sert à utiliser des fonctions en dehors d’une étape data ou d’une procédure. Par exemple, elle peut être ajoutée dans une instruction TITLE.

1. L’objectif pour un programme exécuté le 11 mars 2009

L’objectif de l’exemple qui suit est d’obtenir un fichier .xls nommé class_20090311.xls dont la date change selon le jour de sa création.

La version fixe se présente ainsi : un fichier .xls est créé au moyen de ODS TAGSETS.EXCELXP. Il contient les données du data set SASHELP.CLASS. La création d’un fichier dans la fenêtre OUTPUT est suspendu le temps de la création du fichier .xls au moyen de l’instruction ODS LISTING CLOSE et ODS LISTING.

ods listing close;
ods tagsets.excelxp file='C:/sasref/class_20090311.xls';
proc print data=sashelp.class;
run;
ods tagsets.excelxp close;
ods listing;

2. Ajouter de la flexibilité avec %SYSFUNC

A présent, la date est définie automatiquement au moyen de la macro fonction %SYSFUNC. Cette fonction est dans ce cas particulier composée de deux paramètres :

  • la date SAS extraite au moins de la fonction TODAY()
  • le format à appliquer sur cette date

Résoudre le contenu de la fonction %SYSFUNC grâce aux guillemets doubles : la fonction %SYSFUNC fait partie du langage macro. Dès lors, pour obtenir la résolution de son contenu, il faut utiliser des guillemets doubles.

Retrouver la date d’exécution du programme grâce aux fonctions TODAY() ou DATE () : La fonction TODAY() retourne la date SAS d’exécution du programme. Une alternative est la fonction DATE(). Dans les deux cas, la fonction ne contient pas de paramètre.

Le format YYMMDDn. pour écrire 20090311 : Le format YYMMDDn. est un sous-ensemble de la fonction YYMMDD composée de 8 caractères, sauf indication contraire, faisant apparaître :

  • l’année en premier,
  • suivi du mois en chiffre et
  • enfin du jour.

Ce format avec l’extension « n » a la particularité de ne pas utiliser de symbole ou espace séparatant le jour, du mois et de l’année. Les 8 caractères par défaut de la fonction laisse de la place à une année exprimée par 4 chiffres.

ods listing close;
ods tagsets.excelxp file="C:/sasref/class_%sysfunc(today(),yymmddn.).xls";
proc print data=sashelp.class;
run;
ods tagsets.excelxp close;
ods listing;

3. Tester d’autres formes d’affichage

3.1 Ajouter des tirets bas entre le jour, le mois et l’année grâce à la fonction TRANSLATE

class_2009_03_11.xls : pour avoir des tirets bas (underscore) entre le jour, le mois et l’année, il n’existe pas de format directement applicable. Une solution est alors d’utilise un autre symbole et de le remplacer avec la fonction TRANSLATE.

Ici le format YYMMDD10 retourne une date de la forme 20009-03-11. Les traits d’union (hyphen) sont remplacés par des tirets bas (underscore).

ods tagsets.excelxp file=« C:/sasref/class_%sysfunc(translate(%sysfunc(today(),yymmdd10.),’_’,’-‘)).xls »;

3.2 Ajouter une heure avec TIME() et PICTURE (class_20090311_113057.xls)

Quelle fonction pour l’heure ? : La fonction TIME() retourne l’heure sous la forme d’un time SAS.

Quels formats pour l’heure ? : Le format HHMM. retournera les heures et les minutes, tandis que le format TIME. retournera en plus les secondes. Dans les deux cas cependant, les heures avant 10h apparaissent avec seulement un chiffre : 9:30 et non 09:30. Un espace remplace le zéro manquant.

L’instruction PICTURE de PROC FORMAT pour un format personalisé : Une solution est de créer un format personalisé au moyen de l’instruction PICTURE (PICTURE statement). Comme les lettres H, M et S n’inclus pas de zéro devant (leading zero) pour les nombres à un chiffres, il faut les ajouter dans l’instruction PICTURE.

Note : %0S fait référence aux secondes. Il n’est obligatoire que si vous voulez des secondes dans votre texte final.

proc format;
   picture sasref other=‘%0H%0M%0S’ (datatype=time);
run;

Ensuite, 

  • pour une heure à quatre chiffres (heure + minutes) , il faudra préciser le nombre 4 dans l’appel du format.
  • pour une heures à six chiffres (heures + minutes + secondes), c’est 6 qui doit être ajouté

ods tagsets.excelxp file=« C:/sasref/class_%sysfunc(today(),yymmddn.)_%sysfunc(time(),sasref6.).xls »;

Lectures complémentaires sur http://www.sasreference.fr

ODS

Les fonctions

Les formats :

Les macros fonctions

h1

Combien d’observations dans mon data set ?

avril 14, 2008

Savoir trouver le nombre d’observations dans un data set SAS : tel est le sujet d’aujourd’hui. Connaître le nombre d’observations dans un jeu de données présente plusieurs avantages. En voici deux :

  • Définir une condition pour qu’un code soit exécuté.
  • Définir une boucle pour exécuter un code autant de fois qu’il y a d’observations dans le data set d’origine.

Dans les deux cas, on choisi ici de sauvegarder ce nombre dans une macro variable. Quelles sont les méthodes à disposition pour trouver ce nombre ? Je vous en propose d’en détailler six. Celles-ci fonctionnent également lorsque le data set est vide d’observations.

Exemples illustrés avec le data set ORIG : pour illustrer les différentes méthodes, j’utilise un jeu de données nommé ORIG ne contenant pas d’observations.

data orig;
x=1;

*if x=1 then output;
if x=1 then delete;
run;

L’instruction %PUT permet de voir la valeur de mes macro variables dans la LOG.

1. La fonction COUNT dans PROC SQL : la procédure SQL et sa fonction COUNT permettent de retrouver le nombre total d’observations dans le data set lu, si on n’utilise pas de GROUP BY. L’étoile signifie « TOUTES LES OBSERVATIONS », indépendamment de la variable. Si le nombre d’observations est stocké dans une variable, la valeur s’affiche pour chaque observation. Comme cette valeur est la même pour toutes les observations, on peut n’en afficher qu’une seule via DISTINCT. On peut sauvegarder cette information dans une macro variable via INTO:. Si le DISTINCT n’est pas utilisé, seule la première valeur sera sauvegardé dans la macro variable. DISTINCT est donc optionnel dans ce cas précis.

proc sql noprint;
select distinct count(*) into: methode1
from orig;
quit;

%put METHOD 1 = &methode1. ;


2. SQLOBS, une macro variable automatique à utiliser avec précaution : lorsqu’un data set est créé avec une procédure SQL, on peut, juste après, retrouver l’information avec la macro variable automatique &SQLOBS. Il faut bien faire attention de ne pas inclure d’autres data sets entre temps, lors d’une mise à jour par exemple. SQLOBS récupère le nombre d’observations du dernier jeu de données quelque soit son nom.

proc sql ;
create table methode2 as
select *
from orig;
quit;

%put METHODE 2 = &sqlobs. ;

3. Les métadonnées des dictionnaires SAS : le dictionnaire TABLES liste tous les data sets de toutes les bibliothèques et des informations supplémentaires les caractérisant. Ainsi la variable NOBS contient le nombre d’observations dans le data set. Ici on choisi INTO: pour sauvegarder ce nombre dans une macro variable.

proc sql noprint;
select nobs into: methode3
from dictionary.tables
where upcase(libname)=’WORK’ and
upcase(memname)=’ORIG’;
quit;

%put METHODE 3 = &methode3. ;

4. ATTRN comme « SAS Component Language » ou SCL : le SCL nommé ATTRN permet d’accéder au nombre d’observations. Pour cela, le nom du data set en question et le mot clé NOBS sont données. Ce SCL est accessible via %SYSFUNC. Pour lire le data set et extraire cette information, il faut au préalable, l’ouvrir et ensuite le fermer pour éviter des bugs, via les SCL OPEN et CLOSE. On réfère donc au data set via la macro variable DSID ouvrant le data set.

%let dsid     = %sysfunc(open(work.orig,in));
%let methode4 = %sysfunc(attrn(&dsid,nobs));
%if &dsid. > 0 %then %let rc = %sysfunc(close(&dsid));

%put METHODE 4 = &methode4. ;

5. La variable automatique _N_ : dans un data step, une variable nommée _N_ est créée automatique. Elle contient le nombre total d’itérations effectuées par SAS. Ainsi, si aucune donnée n’est lue, _N_=1. Une fois la lecture d’une observation faite par exemple, SAS revient juste après l’instruction DATA et _N_ est incrémenté de 1. Le nombre d’observations dans le data set est donc _N_-1. Ce nombre est sauvegardé ici dans une macro variable appelée METHODE5 créée via une instruction CALL SYMPUTX.

data_null_;
call symputx(‘methode5’,_N_-1);
set orig;
run;

%put METHODE 5 = &methode5. ;

6.  L’option NOBS de l’instruction SET : en précisant un nom après l’option NOBS= de l’instruction SET, la valeur de NOBS est sauvegardée dans une variable. Ici, elle s’appelle METHODE6. L’instruction CALL SYMPUTX permet de sauvegarder cette valeur dans une macro variable. La manière dont SAS traite le code est très importante ici.  Les explications d’Alain vous sont données plus bas.

data _null_;
if 0 then set orig nobs=methode6;
call symputx(‘methode6’,methode6);
stop;
run;

Le « IF 0 » est une instruction toujours fausse, donc l’exécution de l’instruction
conditionnée ne sera jamais réalisée. La récupération du nombre d’observations
depuis le dictionnaire du data set se fait au moment de la compilation par le SAS DATA
COMPILER, qui stocke dans une variable qui est forcément temporaire citée avec
l’option « NOBS= ».

L’instruction STOP ne permet pas d’écourter le temps de lecture des données car il
n’y pas d’exécution de lecture. Alors que se passe-t-il ?

L’étape DATA étant une boucle automatique dès qu’une instruction de lecture (Set ,
Merge, Modify, Update, …) de data set est détectée par le Superviseur SAS et par
compilateur de l’étape DATA , l’exécution de la boucle est automatique à cause de la
détection de l’instruction « SET » et SAS va vérifier si le test
induit par l’instruction « IF 0 » (comprendre if 0 =1) n’est pas devenu vrai !
D’où la nécessité de poser l’instruction SAS « STOP », pour éviter la boucle de
l’étape DATA.

 

(SUPERVISEUR SAS : Agent pivot qui distribue le code soumis par PARSING, soit au
DATASTEP COMPILER, PROCEDURE PARSER ou au Compilateur MACRO)