Les posteurs les plus actifs de la semaine
Eric Wajnberg
 
zezima
 
Nik
 
margotte185
 
c@ssoulet
 
Coco
 
Ayana
 


Simplification de code ? (boucle, macro)

Voir le sujet précédent Voir le sujet suivant Aller en bas

Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 10:05

Bonjour,


Je cherche un moyen d'obtenir plusieurs valeurs en fonction d'autres, ce pour 2 cas distincts.
VARA : Supposons que ma varA est 1704, sous - entendu le mois d'avril 2017.  J'aimerais trouver un moyen d'obtenir ces mêmes valeurs pour les 5 mois précédents. C'est à dire les valeurs : 1703, 1702, 1701, 1612, 1611.

VARB : Supposons que ma varB est 03, je cherche à obtenir les 5 valeurs précédentes sachant qu'elles vont de 01 à 13, c'est à dire les valeurs : 02, 01, 13, 12, 11.
YEAR : Celle - ci est liée à varB, supposons qu'elle soit égal à 2017, je cherche à diminuer d'une année si et seulement si, ma varB est égale à 13, c'est à dire les valeurs 2017, 2017, 2016, 2016, 2016.

Et ainsi pouvoir intégrer ces valeurs directement dans mes créations de table.
Code:
Exemple :

data want;
set tab_1611
    tab_1612
    tab_1701
    tab_1702
    tab_1703;
run;



J'ai quelques idées de comment m'y prendre, notamment en décomposant ce chiffre en deux parties et à jouer avec les boucles, mais la solution que j'ai écrite semble pouvoir être optimisée.

Code:
%macro _suivi_periode(varA, varB);
 
 
  %if        %substr(&varA.,3,2) ne 01 %then %do;  %let varA1 = %eval(&varA.-1);                  %end;
  %else  %if %substr(&varA.,3,2) eq 01 %then %do;   %let varA1 = %eval(%substr(&varA.,1,2)-1)12;   %end;
  
  %if        %substr(&varA1.,3,2) ne 01 %then %do; %let varA2 = %eval(&varA1.-1);                 %end;
  %else  %if %substr(&varA1.,3,2) eq 01 %then %do;   %let varA2 = %eval(%substr(&varA1.,1,2)-1)12;  %end;
                                                  
  %if        %substr(&varA2.,3,2) ne 01 %then %do; %let varA3 = %eval(&varA2.-1);                 %end;
  %else  %if %substr(&varA2.,3,2) eq 01 %then %do;   %let varA3 = %eval(%substr(&varA2.,1,2)-1)12;  %end;
                                                  
  %if        %substr(&varA3.,3,2) ne 01 %then %do; %let varA4 = %eval(&varA3.-1);                 %end;
  %else  %if %substr(&varA3.,3,2) eq 01 %then %do;   %let varA4 = %eval(%substr(&varA3.,1,2)-1)12;  %end;
                                                  
  %if        %substr(&varA4.,3,2) ne 01 %then %do; %let varA5 = %eval(&varA4.-1);                 %end;
  %else  %if %substr(&varA4.,3,2) eq 01 %then %do;   %let varA5 = %eval(%substr(&varA4.,1,2)-1)12;  %end;

 
 %let year = 20%substr(&varA., 1, 2);
 
 
  %if        &varB. ne 01 %then %do;   %let varB1 = %sysfunc(putn(%eval(&varB.-1), z2.));   %let  year1 = &year.;     %end;
  %else  %if &varB. eq 01 %then %do;     %let varB1 = 13; %let  year1 = %eval(&year.-1);                                %end;  
  
  %if        &varB1. ne 01 %then %do;   %let varB2 = %sysfunc(putn(%eval(&varB1.-1), z2.));  %let  year2 = &year1.;    %end;
  %else  %if &varB1. eq 01 %then %do;    %let varB2 = 13; %let  year2 = %eval(&year1.-1);                               %end;  
  
  %if        &varB2. ne 01 %then %do;   %let varB3 = %sysfunc(putn(%eval(&varB2.-1), z2.));  %let  year3 = &year2.;    %end;
  %else  %if &varB2. eq 01 %then %do;    %let varB3 = 13; %let  year3 = %eval(&year2.-1);                               %end;  
  
  %if        &varB3. ne 01 %then %do;   %let varB4 = %sysfunc(putn(%eval(&varB3.-1), z2.));  %let  year4 = &year3.;    %end;
  %else  %if &varB3. eq 01 %then %do;    %let varB4 = 13; %let  year4 = %eval(&year3.-1);                               %end;  
  
  %if        &varB4. ne 01 %then %do;   %let varB5 = %sysfunc(putn(%eval(&varB4.-1), z2.));  %let  year5 = &year4.;    %end;
  %else  %if &varB4. eq 01 %then %do;    %let varB5 = 13; %let  year5 = %eval(&year4.-1);                               %end;  
 
    
  
 %mend _suivi_periode;
 
%_suivi_periode(1704, 04);


Je n'ai pas l'impression d'être clair ... mais en tout les cas, le code fonctionne.

Mac_Leod.

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 11:12

Bonjour,

voilà ce que j'ai fait.
Je te laisse t'approprier le code et me dire si ça te convient ou pas :-) :

Code:
/*création de la table de test*/
data a;
   input id varA varB $;
   cards;
   1 1704 04
   2 1505 05
   ;
run;

/*on crée la variable année et une variable temporaire*/
data a;
   set a;
   year=2000+int(varA/100);
   temp=(year||varB)*1;
run;

%macro test;

   /*pour l'append*/
   proc delete data=b;
   run;

   /*liste de 1 à 13 et de 1 à 12*/
   %let list_per=;
   %let list_per2=;
   %do i=1 %to 13;
      %let list_per=&i &list_per;
      %if &i<13 %then %do;
         %let list_per2=&i &list_per2;
      %end;
   %end;

   %do i=0 %to 5;
      data a&i;
         set a;

         /*si le numéro de période n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
         if substr(temp-&i,11,2)*1 not in (&list_per) then do;
            temp=temp-&i-100+13;
         end;
         else do;
            temp=temp-&i;
         end;

         /*si le numéro de mois n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
         if substr(varA-&i,11,2)*1 not in (&list_per2) then do;
            varA=varA-&i-100+12;
         end;
         else do;
            varA=varA-&i;
         end;      

      run;
   
      /*on se recalcule les variables varB et year en fonction de temp*/
      data a&i;
         set a&i;
         varB=substr(temp,11,2);
         year=substr(temp,7,4);
      run;

      /*on append dans la table de résultats*/
      proc append data=a&i base=b;
      run;

      /*on supprime les tables intermédiaires*/
      proc delete data=a&i;
      run;
   %end;

   /*on supprime la variable temporaire dans les deux tables*/
   data a;
      set a;
      drop temp;
   run;

   proc sort data=b (drop=temp);
       by id;
   run;

%mend test;

%test;

Niaboc
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 13:31

Je suis en train d'y jeter un oeil et essaye de le comprendre.

J'avoue ne pas comprendre le pourquoi de cette formule :
Code:
if substr(temp-&i,11,2)*1

La variable temp n'a t-elle pas que 6 chiffres ? Comment peut -on dans ce cas récupérer les 11 et 12ème chiffres ?

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 14:21

La variable n'a que 6 chiffres mais le format est best12.

Le substr travaillant sur des caractères, le chiffre est pris comme un caractère. Comme il est incrémenté à droite, il y a 6 espaces vides devant. Et on veut donc récupérer 2 chiffres à partir du 11ème...

Pour être plus propre voici ce que tu peux faire :
Code:
/*création de la table de test*/
data a;
 input id varA varB $;
 cards;
 1 1704 04
 2 1505 05
 ;
run;


%macro test;

 /*on crée la variable année et une variable temporaire*/
 data a;
 set a;
 year=2000+int(varA/100);
 temp=(year||varB)*1;
 run;

 /*pour l'append*/
 proc delete data=b;
 run;

 /*liste de 1 à 13 et de 1 à 12*/
 %let list_per=;
 %let list_per2=;
 %do i=1 %to 13;
 %let list_per=&i &list_per;
 %if &i<13 %then %do;
 %let list_per2=&i &list_per2;
 %end;
 %end;

 %do i=0 %to 5;

 data a&i;
 set a;

 /*si le numéro de période n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
 if substr(put(temp-&i,6.),5,2)*1 not in (&list_per) then do;
 temp=temp-&i-100+13;
 end;
 else do;
 temp=temp-&i;
 end;

 /*si le numéro de mois n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
 if substr(put(varA-&i,4.),3,2)*1 not in (&list_per2) then do;
 varA=varA-&i-100+12;
 end;
 else do;
 varA=varA-&i;
 end;  
 
 run;

 /*on se recalcule les variables varB et year en fonction de temp*/
 data a&i;
 set a&i;
 varB=substr(put(temp,6.),5,2);
 year=substr(put(temp,6.),1,4);
 run;

 /*on append dans la table de résultats*/
 proc append data=a&i base=b;
 run;

 /*on supprime les tables intermédiaires*/
 proc delete data=a&i;
 run;
 %end;

 /*on supprime la variable temporaire dans les deux tables*/
 data a;
 set a;
 drop temp;
 run;

 proc sort data=b (drop=temp);
 by id;
 run;

%mend test;

%test;

où j'ai remplacé les

Code:
if substr(temp-&i,11,2)*1
par
Code:
if substr(put(temp-&i,6.),5,2)*1

pour transformer la variable numérique en caractère sur 6 positions.

En espérant avoir été clair!

Niaboc
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 14:32

Merci, c'est parfaitement clair ! Par souci de compréhension pour d'autres, j'utiliserais cette formule qui offre le format attendu.

Une autre question, y a t-il un moyen de macrotiser ce bout de code en ne spécifiant dans la macro que les varA, et varB ? La création des tables via un cards empêche l'utilisation de toute macro ...

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 14:42

Oui il y a moyen, mais en sortie tu veux quoi du coup?

Une table comme j'ai fait ou les lignes sont démultipliées avec les 5 dates précédentes, ou tu les voudrais en colonne?
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 14:55

Je ne saurais trop m'avancer là dessus.

Je me demande de quelle façon, je vais pouvoir réutiliser ces données dans mes créations de tables à vrai dire. Initialement, chaque valeur était rattaché à une macro à l'aide d'un %let, ce qui me permettait de chacune les appeler.

Du coup, avoir une sortie en ligne ou en colonne, je ne m'imagine pas encore comment je vais pouvoir les récupérer.

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 14:57

on peut s'arranger pour les remettre dans une macro-variable j'imagine. Je regarde ça!
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 15:34

Merci pour ce temps que tu m'accordes !

Pour info, je ne cherche qu'à utiliser ces valeurs selon le nom de mes tables. Comme dans l'exemple plus haut, cela ressemblerais à ça :

Code:
data want;
set tab_1611
    tab_1612
    tab_1701
    tab_1702
    tab_1703;
run;

Ou bien une simple proc sort dont les conditions sont les valeurs que j'essaye de récupérer.


Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 15:52

J'ai écrit ça, qu'à partir de macro-variable du coup.

Le programme créée donc 5 nouvelles macro-variables par variable :
varA1, ---, varA5
varB1, ---, varB5
year1, ---, year5.

Code:
%macro test(varA, varB);

   options minoperator;

   /*on crée la variable année et une variable temporaire*/
   %let year=%sysevalf(2000+%sysfunc(int(&varA/100)));
   %let temp=&year&varB;

   %put ;
   %put la valeur de varA est : &varA..;
   %put la valeur de varB est : &varB..;
   %put la valeur de year est : &year..;
   %put ;

   /*liste de 1 à 13 et de 1 à 12*/
   %let list_per=;
   %let list_per2=;
   %do i=1 %to 13;
      %let list_per=&list_per &i;
      %if &i<13 %then %do;
         %let list_per2=&list_per2 &i;
      %end;
   %end;

   %do i=1 %to 5;

      /*si le numéro de période n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
      %if not(%eval(%substr(%eval(&varA-&i),3,2)*1) in &list_per2) %then %do;
         %let varA&i=%eval(&varA-&i-100+12);
      %end;
      %else %do;
         %let varA&i=%eval(&varA-&i);
      %end;

      /*si le numéro de période n'est plus dans 1 à 13 alors on passe à la 13ème période de l'année précédente*/
      %if not(%eval(%substr(%eval(&temp-&i),5,2)*1) in &list_per) %then %do;
         %let temp&i=%eval(&temp-&i-100+13);
      %end;
      %else %do;
         %let temp&i=%eval(&temp-&i);
      %end;

      %let varB&i=%substr(&&temp&i,5,2);
      %let year&i=%substr(&&temp&i,1,4);

      %put valeur du décalage : &i..;
      %put la valeur de varA&i est : &&varA&i...;
      %put la valeur de varB&i est : &&varB&i...;
      %put la valeur de year&i est : &&year&i...;
      %put ;

   %end;


%mend test;

%test(1704,04);
%test(1505,05);

ça te va?
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 16:26

En dehors de l'adaptation que j'ai dû en faire pour que cela concorde avec mes données, le programme est parfaitement parfait. C'est exactement ce dont j'avais besoin ! Merci à toi !

Je me permet tout de même une petite question. Quelle modif' apporte l'options minoperator à l’exécution du programme ? Est - ce lié à l'utilisation des "IN" pour les listes ?

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par niaboc le Jeu 24 Mar 2016 - 16:31

l'option minoperator permet effectivement de lire l'opérateur "IN" dans un "%IF".

Par défaut SAS ne le comprend pas.
avatar
niaboc

Nombre de messages : 918
Age : 30
Localisation : Paris
Date d'inscription : 05/05/2008

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Mac_Leod le Jeu 24 Mar 2016 - 16:36

Parfait dans ce cas.

Je découvre certaines fonctions, du moins, leur utilisation et je te remercie encore une fois pour m'avoir accordé une bonne partie de ton temps.

Mac_Leod

Nombre de messages : 28
Date d'inscription : 25/06/2015

Voir le profil de l'utilisateur

Revenir en haut Aller en bas

Re: Simplification de code ? (boucle, macro)

Message par Contenu sponsorisé


Contenu sponsorisé


Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum