Techno-conseil sur SASMD 9
par Peter Eberhardt
Combien de fois avez-vous essayé de simplifier votre code à l'aide
des instructions LINK/RETURN ?
Combien de fois vous êtes-vous arraché les
cheveux en tentant de créer des fonctions de macros afin d'encapsuler
la logique d'affaires ?
Combien de fois avez-vous proféré « Si seulement
je pouvais appeler cette étape DATA en tant que fonction » ?
Si l'un de ces énoncés vous décrit, alors vous
aimerez les nouvelles caractéristiques de la procédure PROC FCMP. Si
aucun de ces énoncés ne vous décrit, alors vous avez vraiment besoin
des nouvelles caractéristiques de PROC FCMP.
Ce que je suis sur le point de décrire n'est pas vraiment un techno-conseil,
mais plutôt une brève introduction de la procédure SAS PROC FCMP et
de sa nouvelle capacité permettant de créer vos propres fonctions à
l'étape DATA et routines CALL à l'aide de la syntaxe de l'étape DATA.
Si vous êtes statisticien, vous connaissez peut-être déjà PROC FCMP;
un certain nombre de procédures SAS/STATMD et SAS/ETSMD avaient déjà
la capacité d'appeler des fonctions créées à l'aide de PROC FCMP. Cette
capacité s'étend maintenant au programmeur à l'étape DATA. Pour un
bref aperçu de PROC FCMP, consultez la communication
de Jason Secosky.
Vous pouvez créer des fonctions, comme l'illustre mon exemple. Vous
pouvez également créer des routines d'appel (CALL). Vous pouvez passer
par des tableaux (ARRAYS). Et vos fonctions peuvent même être récursives.
Au bout du compte, PROC FCMP permet l'encapsulation créative de votre
logique de programmation et d'affaires.
Pour commencer :
Vous aurez besoin d'une bibliothèque où stocker
les fonctions. Dans mon exemple, j'utiliserai une bibliothèque WORK.
Même si cela convient au moment de développer vos fonctions, vous
devrez les conserver dans un emplacement permanent où elles seront
accessibles à tous les utilisateurs. Vous devez également indiquer
à SAS où trouver les fonctions; c'est ce que fait l'instruction OPTIONS
CMPLIB=.
Exemple :
Je dois fréquemment effectuer la simple division
de deux valeurs dans un jeu de données. Rien de plus simple, jusqu'à
ce qu'on découvre que certaines des variables ont des valeurs manquantes
de façon inattendue, ou une valeur de 0. Le code suivant montre « l'ancienne
façon », soit en vérifiant explicitement les valeurs avant chaque
division; même avec seulement deux divisions, le code
devient répétitif. La « nouvelle façon » utilise
deux fonctions que j'ai créées pour effectuer les mêmes divisions;
remarquez à quel point le nouveau code est beaucoup plus dépouillé.
* créez un jeu de données de test;
DATA wonkyData;
drop i;
do i = 1 to 100;
if mod(i,3) = 0
then divisor = 0;
else if mod(i,13) = 0
then divisor = .M;
else divisor = i;
dividend1 = (int(ranuni(1) * 10) * i ) + (int(ranuni(2)
* 10) * i );
dividend2 = dividend1 * 2;
output;
end;
RUN;
* traitez les données;
* divByMissingResult réglé à .X manquant pour
que ce soit plus facile à voir;
* un problème commun consiste à utiliser IF
divisor = . ;
DATA oldWay;
set wonkyData;
retain divByZeroResult 0
divByMissingResult1 .X
divByMissingResult2 .F ;
drop divByZeroResult divByMissingResult1 divByMissingResult2;
* seulement 2 tests, mais il pourrait y en
avoir plus;
if divisor = 0 then answer1 = divByZeroResult;
else if missing(divisor) then answer1 = divByMissingResult1;
else answer1 = dividend1 / divisor;
if divisor = 0 then answer2 = divByZeroResult;
else if missing(divisor) then answer2 = divByMissingResult2;
else answer2 = dividend2 / divisor;
run;
*----------------------------------------------;
* répétez, mais utilisez une fonction;
*----------------------------------------------;
* outlib= dit à FCMP où stocker les fonctions;
PROC FCMP outlib=work.funcs.math;
* cette fonction utilise des valeurs explicites pour divByZeroResult
et divByMissingResult ;
FUNCTION divX(dividend, divisor, divByZeroResult,
divByMissingResult);
if divisor = 0 then answer = divByZeroResult;
else if missing(divisor) then answer = divByMissingResult;
else answer = dividend / divisor;
return(answer);
ENDSUB;
* cette fonction utilise des valeurs fixes pour divByZeroResult et
divByMissingResult;
FUNCTION div(dividend, divisor);
if divisor = 0 then answer = 0;
else if missing(divisor) then answer = .F;
else answer = dividend / divisor;
return(answer);
ENDSUB;
RUN;
* indique à SAS où chercher les fonctions;
options cmplib= work.funcs;
* code beaucoup plus simple;
DATA newWay;
set wonkyData;
answer1 = divX(dividend1, divisor, 0, .X);
answer2 = div(dividend2, divisor);
RUN;
* comparez les résultats;
PROC COMPARE BASE=oldWay COMPARE=newWay;
RUN; |