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;
|