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 14-11-2018 08:17:13

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

au hasard (Balthazar)

Sujet un peu plus hardcore cette semaine....

un étudiant m'a contacté pour m'indiquer qu'il avait un problème avec son programme.

Comprenons bien son objectif avant de regarder son programme : il souhaite construire une nouvelle table à partir d'une autre. Jusque là, tout va bien.

mais... (il y a forcément un mais...), il souhaite que chaque observation soit construite en prenant au hasard pour chacune des variables, une des valeurs rencontrée dans la table.
il souhaite donc, pour une observation donnée que la valeur de la première variable soit tirée au hasard, que la valeur de la seconde variable soit elle aussi tirée au hasard, etc. etc. tout en respectant la distribution empirique de ses variables.

Si on applique son idée sur la table SASHELP.CLASS, je peux avoir une observation avec pour valeur de NAME Alfred, puis le sexe de Jane, puis l'age de Joyce, le poids de Robert et la taille de Ronald.

Il a rédigé ce programme (qui fonctionne parfaitement) :

Code:

data boot_class;
   do i=1 to 20;
      selectx1 = ceil(ranuni(-123456)*n);
      set sashelp.class(keep=name) point=selectX1 nobs=n;
      selectx1 = ceil(ranuni(-123456)*n);
      set sashelp.class(keep=sex) point=selectX1 nobs=n;
      selectx1 = ceil(ranuni(-123456)*n);
      set sashelp.class(keep=age) point=selectX1 nobs=n;
      output;
   end;
   stop;
run;

ce programme permet de créer une table de 20 observations.

Avant chaque instruction SET, on tire un chiffre au hasard compris entre 1 et N, le nombre d'observations de la table.

et là, vous allez me dire : "mais d'où vient ce nombre d'observations ?"
et je vous réponds : "de l'option NOBS= de l'instruction SET"
vous me répondrez "mais l'instruction SET apparaît APRES le premier usage de N"
et là, je vous dirai "pas d’inquiétude : au moyen de l'option NOBS= vous créez un marqueur qui aura pour valeur le nombre d'observations de la table et qui sera créée au cours de la phase de compilation du programme. Lorsque le programme est compilé, SAS va accéder aux métadonnées de la table citée après l'instruction SET et donnera sa valeur à N.

Au moment de l'exécution, et donc au moment du calcul de la modalité de SELECTX1, N sera connu et pourra donc être utilisé.

petite remarque : l'option NOBS= est précisée dans chaque instruction SET. C'est inutile, il suffit que cette option apparaisse une seule fois, dans n'importe quelle instruction SET et le programme fonctionnera quand même.

reprenons : je dispose d'un nombre au hasard compris entre 1 et N, disons 12. Au moyen de l'option POINT= de l'instruction SET, j'accède directement à la 12ème observation et je conserve la valeur de NAME pour cette 12ème observations.

je tire ensuite une deuxième fois un nombre au hasard entre 1 et N, disons 4, et au moyen de POINT=, j'accède directement à la 4ème observation pour ne conserver que la valeur de SEX.

On recommence ensuite...

bref... on arrive à construire cette table :

Code:

Obs.     i    Name       Sex    Age

  1      1    Joyce       F      11
  2      2    Jeffrey     M      13
  3      3    Philip      F      15
  4      4    Ronald      F      12
  5      5    Louise      F      12
  6      6    Robert      F      12
  7      7    Joyce       F      12
  8      8    Alice       F      15
  9      9    Ronald      F      15
 10     10    John        M      15
 11     11    Thomas      F      15
 12     12    Carol       M      15
 13     13    Robert      F      15
 14     14    Barbara     M      15
 15     15    Louise      F      14
 16     16    William     M      15
 17     17    Alfred      F      14
 18     18    Thomas      M      14
 19     19    John        M      12
 20     20    Mary        F      14

Si ça marche, quelle est le problème ?

le problème, c'est que mon étudiant ne travaille pas avec une table contenant quelques variables. Sa table contient plus de 30 variables et il n'a pas vraiment envie d'écrire un programme avec plus de trente instructions de tirage d'un nombre au hasard et plus de 30 instructions SET en modifiant à chaque fois la variable à conserver.

il souhaite quelque chose d'un peu plus "automatique"....

Alors il m'a proposé ça :

Code:

Data boot_class;
   length  x_var $ 50;
   Do i=1 to 20;
      Do x_var='name','sex','age','height','weight' ;
        select_obs = ceil(ranuni(-123456)*n);
        set sashelp.class(keep=x_var) point=select_obs nobs=n;
      end;
      output;
   end;
   stop;
run;

et là, ça ne fonctionne pas du tout...

vous avez en effet dans votre journal le message suivant :

Code:

ERROR: La variable x_var de la liste DROP, KEEP ou RENAME n'a jamais été référencée.

ben oui....

sashelp.class(keep=x_var)

mon étudiant demande à conserver de la table SASHELP.CLASS la variable x_var qui n'existe pas dans cette table...
il aurait bien voulu que SAS, automatiquement, remplace X_VAR par sa valeur mais ça, ça n'est pas possible....

alors ? comment faire pour mon étudiant ne soit pas obligé d'écrire plus de 30 blocs de SELECTX1= / SET ?

amusez vous bien et à la semaine prochaine

Hors ligne

 

#2 21-11-2018 16:35:15

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

Re: au hasard (Balthazar)

Alors, ce grand mélange, comment le faire....

notre principale problème, c'est l'option de table KEEP= (on aurait les mêmes problèmes avec l'instruction KEEP).

Après KEEP=, SAS n'attend qu'un nom (ou plusieurs noms) de variables. Il n'est donc pas question de mettre un nom de variable en espérant qu'il devinera la modalité et même de mettre une fonction SAS en espérant qu'il va l'exécuter...

une instruction du type :

Code:

set sashelp.class(keep=scan("sex age name weight height",2)

ne fonctionnera jamais...

vous devez impérativement préciser un ou plusieurs noms de variables.... mais vous pouvez tout à fait citer une macro-variable qui contiendrait un ou plusieurs noms de variables....

voici une première proposition (qui est critiquable et que vous aurez à améliorer pour la semaine prochaine...

Code:

%let liste=name sex age height weight ;

data _null_;
do j=1 to countw("&liste");
   call symputx(compress("var"||j),scan("&liste",j));
   call symputx("nvar",j);
end;
run;

%macro boot ;
Data boot_class;
   Do i=1 to 20;
      %Do j=1 %to &nvar ;
        select_var = ceil(ranuni(-123456)*n);
        set sashelp.class (keep=&&var&j) point=select_var nobs=n;
      %end;
      output;
   end;
   stop;
run;
%mend ;

on commence par créer une macro variable qui va contenir les noms de toutes les variables de votre table (c'est cette phase qui est critiquable... si votre table contient 200 variables, ça risque d'être pénible).

Une étape DATA _NULL_ ensuite pour créer autant de macro-variables VAR1, VAR2, VAR3... que nous avons de variables dans la liste et une macro variable NVAR qui nous indique combien nous avons de variables.

Ensuite, au sein d'un macro programme (c'est obligatoire puisqu'on utilise une boucle %DO qui ne peut pas être utilisée en programmation ouverte), au moyen de la boucle %DO, le code que nous ne voulions pas écrire (parce trop long et répétitif) sera généré.

et voilà !

mais bon... il devrait y avoir moyen d'éviter la création de la macro variable LISTE et la saisie "à la main" de l'ensemble de variables de la table que l'on souhaite manipuler...

je vous laisse réfléchir à cela....

à la semaine prochaine...

Hors ligne

 

#3 12-12-2018 10:46:13

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

Re: au hasard (Balthazar)

je viens de me rendre compte que je n'avais pas posté le 21 novembre dernier la suite de ce sujet (alors que les personnes inscrites sur ce site y avaient, elles, accès...)

Reprenons.

il est parfaitement inutile de saisir à la main (et donc avec des risques d'erreur...) la liste de variables d'une table puisque cette information est déjà présente dans votre environnement SAS.

Les noms des variables d'une table sont en effet forcément présents dans la table dictionnaire COLUMNS (si la table appartient à une bibliothèque reconnue par SAS, bien entendu).

Dès lors, si vous souhaitez disposer dans des macros variables, des noms des variables de la table SASHELP.CLASS, un peu de PROC SQL suffit :

Code:

PROC SQL NOPRINT;
   select name into :var1-:var9999 from dictionary.columns where libname="SASHELP" and memname="CLASS";
   %let nvar=&sqlobs ;
quit;

et le macro-programme boot n'a même pas besoin d'être modifiée...

tiens... en parlant de macro programme... et si, pour la semaine prochaine vous construisiez un macro programme qui aura en paramètre :
1- la bibliothèque dans laquelle est la table
2- le nom de la table à manipuler
3- le nombre d'observations à créer
4- le nom de la table à produire ?

ça devrait vous prendre 5 minutes...

à la semaine prochaine

Hors ligne

 

#4 12-12-2018 10:56:29

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

Re: au hasard (Balthazar)

ça prenait tellement 5 minutes que je vous ai donné deux semaines pour le faire...

ce macro programme, le voici :

Code:

%macro golgoth(lib,tab,tabprod,obs);

PROC SQL NOPRINT;
   select name into :var1-:var9999 from dictionary.columns where libname=upcase("&lib") and memname=upcase("&tab");
   %let nvar=&sqlobs ;
quit;

Data &tabprod;
   Do i=1 to &obs;
      %Do j=1 %to &nvar ;
        select_var = ceil(ranuni(-123456)*n);
        set &lib..&tab (keep=&&var&j) point=select_var nobs=n;
      %end;
      output;
   end;
   stop;
run;

%mend ;

%golgoth(sashelp,class,boot,30);

le premier paramètre, c'est la bibliothèque qui contient la table que vous allez utiliser en entrée, le second paramètre est le nom de la table. En troisième paramètre, vous devez indiquer la nom de la table à créer (qui sera impérativement produite dans la bibliothèque de travail). En dernier paramètre, vous indiquez le nombre d'observations que doit contenir la table à produire.

une petite remarque concernant la clause WHERE :

Code:

where libname=upcase("&lib") and memname=upcase("&tab");

on oublie très souvent que dans les tables bibliothèque, les noms des tables et bibliothèques sont systématiquement mis en majuscules...

ce sujet est maintenant terminé - à bientôt pour un nouveau sujet des beaux mercredis

Hors ligne

 

Pied de page des forums

Propulsé par FluxBB
Traduction par FluxBB.fr
Flux RSS