Annonce

Bienvenue sur le site support des ouvrages :
SAS - Introduction au décisionnel : méthode et maîtrise du langage
(1ère édition - épuisée)
SAS - Introduction pratique : du data management au reporting (2ème édition - épuisée)
SAS - Introduction au décisionnel : du data management au reporting (3ème édition - épuisée (hélas...))

la réponse à la question "mais où trouver la 3ème édition ?" est précisée ici


Retrouvez dans ce tiré à part, la préface écrite par Mouloud Dey, Directeur Business solutions et marchés émergents, SAS France,
l’introduction générale ainsi que le plan complet de l’ouvrage

#1 11-10-2017 06:38:13

SAS-SR
Administrateur
Lieu: Université d'Orléans
Date d'inscription: 01-09-2008
Site web

Min et Max sont dans un bateau

Deux exercices en un cette semaine....

Le programme suivant crée la table TEST :

Code:

Data test(drop=i);
   call streaminit(123456);
   do i=1 to 50;
      x=int(rand("uniform")*50);
      output;
   end;
run;

On souhaite obtenir une table qui vous donnera le minimum et le maximum de X :
http://www.sas-sr.com/img/minmax1.png

Facile me direz vous et vous imaginez déjà que vous allez passer par PROC MEANS et la création d'une table de résultats.

Si vous vous dites cela, c'est que vous ne me connaissez pas encore.... vous allez devoir obtenir ce résultat au moyen d'une unique étape DATA (et d'un proc print;run; bien entendu).

Et comme c'est (presque) simple, vous vous amuserez aussi avec cette seconde table :

Code:

data test3(drop=i);
   call streaminit(123456);
   length client $ 7 ;
   do client='Pierre','Paul','Jacques';
      do i=1 to 50; 
         x=int(rand("uniform")*50);
         output;
      end;
   end;
run;

il s'agit ici, et toujours au moyen uniquement d'une étape DATA d'obtenir une table de trois observations, vous présentant, pour chaque client, les valeurs min et max prises par X. Vous avez droit, suite à votre étape DATA à un "proc print;run;"

Vous obtiendrez ceci :
http://www.sas-sr.com/img/minmax2.png

Je réponds à l'avance à la question que certains ne manqueront pas de me poser "mais on ne peut pas utiliser, avant l'étape DATA, une procédure (au hasard... PROC SORT) ?" - la réponse est 'non'... uniquement une étape DATA

et si vous vous dites "c'est facile, faut faire ça et ça", faites le et vérifiez que vous obtenez bien le résultat attendu...

Ne spoilez pas ce sujet des beaux mercredis en postant votre réponse dans le forum de discussions, envoyez moi un mail ;-)

à la semaine prochaine

Hors ligne

 

#2 Hier 08:10:13

SAS-SR
Administrateur
Lieu: Université d'Orléans
Date d'inscription: 01-09-2008
Site web

Re: Min et Max sont dans un bateau

J’ai reçu pas mal de propositions de solution à ce sujet des beaux mercredis et la plupart d’entre elles étaient vraiment compliquées…

Alors voyons cela…

Déjà, face au problème posé et puisque vous n’avez droit qu’à une étape DATA, vous devez vous dire que s’il faut connaitre les valeurs min et max de la variable X, ceci n’est possible que si vous avez examiné l’ensemble des valeurs prises par X.

C’est donc à la dernière exécution du programme (puisque votre programme SAS sera en réalité exécuté autant de fois qu’il y a d’observations dans votre table) que vous allez connaître la valeur min et la valeur max. On peut donc être certain d’avoir besoin du marqueur END et votre programme, à compléter, aura la structure suivante :

Code:

Data test2 ;
   Set test end=dernier;
   *** à completer *** ;
   If dernier then output;
   Drop x ;
Run;

Ensuite, puisqu’on ne peut connaître la valeur de min et max qu’au terme de l’ensemble des exécutions du programme, vous devez aussi vous dire que nos variables MIN et MAX vont voir leurs valeurs évoluer au cours des exécutions et, forcément, vous allez devoir, au cours d’une exécution donnée, savoir quelles valeurs avaient MIN et MAX à l’exécution précédente… vous avez donc besoin de RETAIN !

Code:

Data test2 ;
   Set test end=dernier;
   Retain min max ;
   *** à completer *** ;
   If dernier then output;
   Drop x;
Run;

La question de l’initialisation des variables MIN et MAX se pose maintenant (essentiellement pour la variable MIN).

Si vous ne donnez pas une valeur à min, alors MIN sera au départ valeur manquante. Mais ce que votre programme doit faire, c’est comparer la valeur de X avec la valeur de MIN, si X est inférieur à MIN, alors il faut modifier la valeur de MIN et lui donner une valeur égale à celle de X.

Si MIN est au départ valeur manquante et puisque la valeur manquante est inférieure à tout, aucune valeur de X ne sera inférieure à valeur manquante et la valeur de MIN (valeur manquante) ne sera jamais modifiée.

Dans toutes les propositions que j’ai reçues, lest valeurs de MIN et MAX ont été fixées arbitrairement (pour min 0, 100000  …) : ce n’est pas la manière correcte de faire.

Vous prenez un risque parce que, en fonction de la valeur que vous allez donner, vous pouvez vous retrouver avec un résultat final différent. Il faut rendre vos programmes « insensibles » à vos données et ne jamais fixer un paramètre de votre programme en fonction de ce que vous observez dans votre table.

Certains me répondront « mais j’ai le bon résultat !» et je répondrai (sèchement…) : « on s’en fiche, ce qui compte, c’est la manière d’obtenir ce résultat qui compte ».

Alors comment faire ?

Et bien comme ceci :

Code:

Data test2 ;
   Set test end=dernier;
   Retain min max ;
   If _n_=1 then do ;
      Min=x;
      Max=x;
   End;
   *** à completer *** ;
   If dernier then output;
   Drop x;
Run;

Ensuite, il ne reste plus grand chose à ajouter pour obtenir le résultat souhaité :

Code:

Data test2 ;
   Set test end=dernier;
   Retain min max ;
   If _n_=1 then do ;
      Min=x;
      Max=x;
   End;
   If x>max then max=x;
   If x<min then min=x;
   If dernier then output;
   Drop x;
Run;

Et voilà !

Passons au second problème. Lorsque vous avez vu dans le texte de l’exercice que vous ne deviez utiliser qu’une étape DATA et que vous n’aviez pas le droit d’utiliser une autre procédure que PROC PRINT, vous vous êtes dit « mince… PROC SORT m’aurait bien été utile »

Si si… vous vous êtes dit cela… on souhaite en effet ne conserver de TEST3 qu’une ligne par client, comme les valeurs de min et max ne peuvent être connues que lorsqu’on a examiné l’ensemble des observations relatives à un client, vous vous êtes dit que votre programme devait avoir la structure suivante :

Code:

Data test4 ;
   Set test3 ;
   By client;
   *** à completer *** ;
   If last.client then output;
   Drop x;
Run;

Hélas, vos espoirs ont été anéantis puisque vous n’aviez pas le droit d’utiliser PROC SORT…. Et puisque la table n’est pas naturellement triée en fonction des valeurs de CLIENT, c’est mort…

Et bien non… si vous vous êtes dit que c’était foutu, c’est que vous ne connaissez pas l’option NOTSORTED de l’instruction BY présente dans une étape DATA (je ne peux pas vous en vouloir, je ne la cite pas dans l’édition 3… mais il me semble que je la citais dans les éditions 1 et 2 (vous n’avez pas l’intégrale de mes œuvres ??? c’est une erreur !).

Quand pouvez-vous vous servir de l’option NOTSORTED ?

Aujourd’hui ! Notre table TEST3 n’est pas triée en fonction des valeurs de CLIENT mais les observations sont regroupées par valeurs de CLIENT : les cinquante premières observations sont relatives à Pierre, les cinquante suivantes concernent Paul etc. On va alors pouvoir se servir de FIRST et LAST si on ajoute cette option NOTSORTED à notre instruction BY. La table n’est pas triée, mais ça n’est pas grave !

Votre programme peut donc avoir la forme suivante :

Code:

Data test4 ;
   Set test3 ;
   By client NOTSORTED;
   *** à completer *** ;
   If last.client then output;
   Drop x;
Run;

La suite ?

Très proche de ce que nous avons fait dans la première partie :

MIN et MAX sont des variables RETAIN, et il faut les initialiser. Cette initialisation doit s’effectuer à chaque fois que l’on aborde un nouveau client. En effet, si vous vous contentez d’une initialisation identique à celle proposée dans le premier exercice, vous allez avoir un problème :

Code:

   If _n_=1 then do ;
      Min=x;
      Max=x;
   End;

Pour notre premier client, les valeurs MIN et MAX vont bien être égales au min et au max de Pierre, mais pour le second client, au lieu du min et max de Paul, vous aurez le min et max de Paul et Pierre et pour le troisième client, vous aurez le min et max de la table entière.

Pour initialiser MIN et MAX lorsqu’on aborde un nouveau client, on procèdera donc ainsi :

Code:

   if first.client then do ; 
      min=x ; 
      max=x;
   end;

Le programme complet aura donc la forme suivante :

Code:

data test4;
   set test3;
   by client notsorted;
   retain min max ;
   if first.client then do ; 
      min=x ; 
      max=x;
   end;
   if x>max then max=x;
   if x<min then min=x;
   if last.client then output;
   drop x;
run;

Plus haut, j’indique qu’en aucun cas vous ne devez paramétrer votre programme en fonction de ce que vous observez dans la table.

D’une certaine façon, je le fais quand même ici puisque mon programme ne fonctionne que si les observations de la table sont regroupées par client… mais c’est là ma seule entorse à ma règle !

Donnez-moi une autre table avec d’autres clients (3, 10, 500, 2 000 000 si vous voulez), tant que les observations sont regroupées par client, le programme fonctionnera.

Ensuite, si les observations ne sont pas regroupées, alors évidemment, le programme ne fonctionnera plus (et pour qu’il fonctionne à nouveau… PROC SORT obligatoire…).

Je vous laisse réfléchir à tout ça…

à la semaine prochaine pour un nouveau sujet des beaux mercredis

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB
Traduction par FluxBB.fr
Flux RSS