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 19-09-2018 14:53:21

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

Les beaux mercredis - saison 8

et c'est reparti pour une nouvelle saison des beaux mercredis !

on va commencer gentiment... (parce que je souhaite que mes étudiants en M1 se creusent un peu la tête en réfléchissant à ce petit problème).

Le programme suivant va créer une table :

Code:

DATA test(KEEP=x) ;
   DO i=1 to CEIL(RAND('uniform')*100);
      x=ROUND(RAND('uniform')*100);
      OUTPUT;
   END;
RUN;

l'objectif est d'obtenir, au moyen d'une seule et unique étape DATA, une table dans laquelle seront présentes uniquement deux variables, MAX1 et MAX2 qui auront pour modalité la valeur de X la plus élevée (MAX1) et la seconde valeur de X la plus élevée (MAX2).

(ne spoilez pas l'exercice : si vous avez trouvé la solution, ne la postez par dans la section forum de discussions)

amusez vous bien

Hors ligne

 

#2 26-09-2018 15:41:57

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

Re: Les beaux mercredis - saison 8

Donc....

on veut créer au moyen d'une unique étape data une table qui contiendra deux variables reprenant les deux valeurs les plus élevées de X.

procédons dans l'ordre... votre programme doit donc avoir la forme suivante :

Code:

data test2(keep=max1 max2);
   set test ;
   ***;
run;

pour connaître les deux valeurs les plus élevées, il est nécessaire d'examiner l'ensemble des observations de la table et on ne peut donc produire l'observation désirée que lorsque que, dans le PDV, on traitera la dernière observation.

Le programme devient :

Code:

data test2(keep=max1 max2);
   set test end=last ;
   ***;
   if last ;
run;

Lorsque l'on traite une certaine observation, quand débute le programme, il faut que SAS connaisse les deux valeurs les plus élevées vues jusqu'à maintenant.
Comment pourrait-il savoir si le X traité dans le PDV est supérieur, ou pas, aux valeurs MAX1 et MAX2 sinon ?

il faut donc donner à SAS la capacité de se souvenir ce qu'il a vu "avant" : nos variables MAX1 et MAX2 sont donc forcément des variables RETAIN :

Code:

data test2(keep=max1 max2);
   set test end=last ;
   retain max1 max2 ;
   ***;
   if last ;
run;

et voilà, nous avons posé le cadre nécessaire à la réussite de notre programme. Il ne nous reste plus qu'à écrire le programme proprement dit :

Code:

data test2(keep=max1 max2);
   set test end=last ;
   retain max1 max2 ;
   if x>max1 then do ;
      max2=max1;
      max1=x;
   end;
   else if x>max2 then max2=x; 
   if last ;
run;

Comment vérifier que l'on a bien la bonne réponse ? au moyen de proc univariate qui vous permet, dans un des tableaux de sortie, de voir les 5 valeurs les plus faibles.

Si vous avez du mal à voir comment fonctionne ce programme, regardez votre table et demandez vous, après chaque exécution, la valeur prise par max1 et max2...

soit une table de 4 observations :

Code:

   X
  19
  58
  55
  12

après la phase de compilation du programme, vous avez la phase d'initialisation du PDV. Ainsi quand débute la première exécution, MAX1 et MAX2 sont tous les deux égaux à valeur manquante.

arrive X=19 dans le PDV

est ce que 19>MAX1 ?
oui, donc MAX2=MAX1 et comme MAX1=valeur manquante, MAX2, vaudra valeur manquante. MAX1=19 suite à cette première exécution.

Passons à la seconde : X=58
est ce que 58>MAX1 (égal pour l'instant à 19) ?
oui, donc MAX2=MAX1 (qui est pour l'instant égal à 19), puis MAX1=X=58.

A la suite de la seconde exécution, MAX1=58 et MAX2=19

passons à la troisième exécution : x=55
est ce que 55>MAX1 (égal pour l'instant à 58) ?
non
est ce que 55>MAX2 ?
oui, donc MAX2=55 (et MAX 1 reste à 58)

4ème exécution : X=12
est ce que 12>MAX1 (égal pour l'instant à 58) ?
non
est ce que 12>MAX2 (égal pour l'instant à 55) ?
non

donc rien ne change...

Voyons si vous avez compris : modifiez le programme et obtenez maintenant, au lieu des deux valeurs les plus élevées, les deux valeurs les plus faibles.

à la semaine prochaine

Hors ligne

 

#3 03-10-2018 15:08:12

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

Re: Les beaux mercredis - saison 8

Reprenons

vous vous êtes peut être dit que, pour répondre à la nouvelle question, il suffisait de remplacer MAX par MIN et les opérateurs > par <.

Vous avez alors peut être rédigé ce programme :

Code:

data test2(keep=min1 min2);
   set test end=last ;
   retain min1 min2 ;
   if x<min1 then do ;
      min2=min1;
      min1=x;
   end;
   else if x<min2 then min2=x; 
   if last ;
run;

et évidemment, le résultat n'est pas à la hauteur de vos espérances puisque vous obtenez, pour MIN1 et MIN2, valeur manquante....

pourquoi ?

et bien tout simplement parce que les valeurs manquantes sont inférieures à tout.

Suite à l'initialisation de l'exécution, au début de la première exécution, MIN1 et MIN2 sont valeurs manquantes. La condition if X<MIN1 ne sera donc jamais vraie et vous terminerez forcément avec MIN1 et MIN2 tous les deux égaux à valeur manquante.

Si vous avez compris la raison de ce premier résultat, vous avez aussi compris ce qu'il faut faire : il ne faut pas que, lorsque débute la première exécution, les valeurs de MIN1 et MIN2 soient en valeur manquante.

Comment faire ?

ben... il suffit de donner des valeurs initiales à MIN1 et MIN2 :

Code:

data test2(keep=min1 min2);
   set test end=last ;
   retain min1 min2 (1E12 1E12);
   if x<min1 then do ;
      min2=min1;
      min1=x;
   end;
   else if x<min2 then min2=x; 
   if last ;
run;

Nous avons choisi de donner une valeur arbitrairement élevée à MIN1 et MIN2 (10 puissance 12) pour espérer être tranquille mais la bonne exécution de ce programme dépend de ces valeurs : si vos X sont tous supérieur à 10^12, vous n'aurez pas le bon résultat (c'est bien entendu impossible avec le programme qui crée la table TEST).

Je conseille toujours à mes étudiants de prendre l'habitude de rendre leur programme complètement indépendant des données que ces programmes vont manipuler (prudence est mère de sureté).

Comment faire ici pour rendre notre programme "tout terrain" ?

de la façon suivante :

Code:

data test2(keep=min1 min2);
   set test end=last ;
   retain min1 min2 ;
   if _n_=1 then do ;
      min1=x;
      min2=x;
   end;
   if x<min1 then do ;
      min2=min1;
      min1=x;
   end;
   else if x<min2 then min2=x; 
   if last ;
run;

et là, vous êtes tranquille....

sauf que.... imaginons que X puisse être valeur manquante...

comment faire pour obtenir, à coup sûr, les deux valeurs les plus faibles, valeur manquante exclue ?

le programme suivant vous crée une table susceptible de contenir des X ayant pour valeur la valeur manquante :

Code:

DATA test(KEEP=x) ;
   DO i=1 to CEIL(RAND('uniform')*100);
      x=ROUND(RAND('uniform')*100);
      IF RAND('uniform')<0.25 then x=.;
      OUTPUT;
   END;
RUN;

amusez vous bien et à la semaine prochaine

Hors ligne

 

#4 10-10-2018 15:44:35

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

Re: Les beaux mercredis - saison 8

autant vous le dire, pour la dernière question de ce sujet, j'avais envisagé quelque chose d'un peu compliqué alors qu'une solution TRES simple existe (et que Naira - merci à elle - m'a envoyé par email).

Les valeurs manquantes vous gênent ? alors il suffit de ne pas les prendre en compte...

Code:

data test2(keep=min1 min2);
   set test(WHERE=(x is not missing)) end=last ;
   retain min1 min2 ;
   if _n_=1 then do ;
      min1=x;
      min2=x;
   end;
   if x<min1 then do ;
      min2=min1;
      min1=x;
   end;
   else if x<min2 then min2=x; 
   if last ;
run;

il n'y a pas plus simple !

Ce sujet est maintenant terminé, à 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