1
votes

Comparaison des valeurs numériques macro

J'essaye de comparer deux valeurs numériques dans une macro. Mais je continue de recevoir le message suivant:

%macro fail;
      %do i=0 %to 0.2 %by 0.05;
          data failcrs;
              set fail;
              if f_p>=input(&i, 8.) then output;
          run;
      %end;
%mend failcrs;

Mon code est le suivant:

ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 0.2
ERROR: The %TO value of the %DO I loop is invalid.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was: 0.05
ERROR: The %BY value of the %DO I loop is invalid.
ERROR: The macro FAIL will stop executing.

f_p est une variable numérique.

Quel est le problème avec mon code? Veuillez aider.

Merci beaucoup!


3 commentaires

Faire fonctionner cela est facile, mais le code est illogique et probablement pas ce que vous voulez. Si c'est un cas de test, je suppose que ça va.


Je ne vois pas où vous comparez les variables macro? Si vous voulez opérer sur des valeurs à virgule flottante dans le code de macro, vous devez utiliser % sysevalf () au lieu de l'appel de fonction implicite % eval () que les instructions de macro utilisent normalement. % if% sysevalf (& I> = 0.2)% alors ...


Merci Tom! J? ai compris. Une autre fonction macro.


5 Réponses :


0
votes

Essayez d'utiliser best32. Mais pourquoi voulez-vous faire une boucle, lorsque votre ensemble de données est écrasé pour chaque boucle. Veuillez vérifier le journal pour chacune des étapes ci-dessous. Comme à @Reeza dans les commentaires explique ci-dessous, vous ne faites même pas une déclaration d'entrée Options mprint;

   /* do this*/
    %macro fail;
   %let i =15;
    data failcrs;
          set sashelp.class;

          if age lt input(&i, best32.)  then output;
      run;
   %mend fail;

  %fail

   /* dataset overwritten every time to finally pick up 15 as value check in the log*/
   %macro fail1;
   %do i = 1 %to 15;
    data failcrs1;
          set sashelp.class;

          if age lt input(i, best32.) then output;
      run;
  %end;
 %mend fail1;

%fail1


3 commentaires

Changé la réponse, mais votre commentaire lui-même est la réponse. Vous avez raison @Reeza


Le problème est avec les valeurs décimales dans la boucle do, c'est ce qui génère l'erreur. Je ne sais pas s'ils sont valides dans une boucle% DO.


Merci beaucoup à vous tous! J? ai compris. Le problème est donc la décimale. Maintenant, le code fonctionne. Je vais faire quelques comptages et fusionner après la sortie, c'est long, donc je n'ai pas collé les codes restants ici.



0
votes

Vous rencontrez quelques problèmes. Les boucles de macro fonctionnent mieux avec les entiers, mais une solution de contournement simple est une boucle% DO% UNTIL à la place.

  1. Le nom de% MEND est différent de celui de% MACRO
  2. Valeurs non valides pour la boucle% DO% I.
  3. Nom de jeu de données non unique, ce qui signifie que la sortie s’écrase elle-même.

    *fake data to work with;  
    data fail;
        do f_p=0 to 0.2 by 0.01;
            output;
        end;
    run;
    
    %macro fail;
        %let i=0;
          %do %until(&i = 0.2); /*2*/
              data failcrs_%sysevalf(&i*100); /*3*/
                  set fail;
                  if f_p>=&i then output;
              run;
              %let i = %sysevalf(&i + 0.05);
          %end;
    %mend fail; /*3*/
    
    *test macro;
    %fail;
    

Les chiffres dans les commentaires correspondent aux problèmes identifiés.


6 commentaires

Merci beaucoup Reeza! J'ai toujours pensé que la valeur de toute macro-variable est caractéristique, même si elle est affectée d'une valeur numérique. hmm, où ai-je eu une telle idée?


Je pense juste à quoi ressemblera le code généré et si cela a du sens. En général, les variables macro sont du texte, pas des nombres ou des caractères si cela le rend plus clair.


Je dois dire: non, je suis encore déroutant. Le texte n'est donc pas un caractère? Vous voulez voir le code macro complet? Je peux le coller ici pour vous montrer. Peut-être pouvez-vous identifier d'autres problèmes.


C'est vraiment une question trop longue à répondre dans les commentaires et n'a aucun rapport avec votre question initiale. Le code généré était input (0.01, 8.) et qui n'est pas valide car 0.01 est déjà numérique. Si vous vouliez rendre cela valide, vous pouvez également le corriger en le faisant générer input ("0.01", 8.) , qui serait techniquement valide. Ce n'était pas la partie qui causait l'erreur de toute façon, c'était la boucle DO, c'est juste un problème différent que j'ai remarqué également.


Cela aurait été input ("& i", 8.) .


Merci encore beaucoup Reeza! Je vais faire une étude complète sur les variables macro et les fonctions macro. Merci pour votre temps. Apprécié.



0
votes
%macro fail;
        %let i=0;
        %do %until(&i = 0.2);
            data failcrs; 
                set crse_grade_dist_fail;
                if f_p>=&i then output;
                run;

        proc sql;
            create table count_failclass as
            select strm, count(class_nbr) as numfclass_%sysevalf(&i*100)
            from failcrs
            group by strm;
        quit;

        proc sql;
            create table failfaculty as
            select strm, instructor_id, instructor, count(class_nbr) as numfclass
            from failcrs
            group by strm, instructor_id, instructor;
        quit;

        proc sql;
            create table count_failfaculty as
            select strm, count(instructor) as numffaculty_%sysevalf(&i*100)
            from failfaculty
        group by strm;
        quit;

        data count_class_faculty;
            set count_class_faculty;
            set count_failclass;
            set count_failfaculty;
        run;

        %let i = %sysevalf(&i + 0.05);
    %end;
%mend fail;
Good thing is my data doesn't have f_p=0, all of them is greater than zero. Because I only want to count failed courses.

2 commentaires

N'utilisez pas de tests d'égalité pour les nombres à virgule flottante en raison de l'impossibilité de représenter exactement les fractions décimales en nombres binaires. % do% jusqu'à (% sysevalf (& i> = 0.2));


Tom, t'as! J'ai appris quelques trucs. Merci beaucoup encore une fois!



0
votes

Les tests conditionnels en code macro (% if , % jusqu'à , % while , etc.) utilisent % eval () fonction de macro qui ne fait que l'arithmétique entière. Cela inclut les incréments et les tests effectués dans une boucle% do-% to-% by.

Pour utiliser l'arithmétique en virgule flottante, vous devez utiliser la fonction macro % sysvalf () .

Vous pouvez coder vos propres incréments dans le compteur de boucle.

%do j=0 %to 20 %by 5 ;
   %let i=%sysevalf(&j/100);
   ...
%end;

Ou faire du compteur de boucle un entier et utiliser une autre variable macro pour contenir la fraction.

%let i=0;
%do %while( %sysevalf( &I <= 0.2 ) );
   ...
   %let i=%sysevalf(&i + 0.05);
%end;


0 commentaires

0
votes

La documentation est écrite pour être lue, une simple recherche de "SAS 9.4 Macro Do" devrait tout expliquer - start, stop et by sont des entiers - des entiers dans le sens où toute expression de macro source à leur place évalue implicitement ou explicitement à un entier au besoin.

La macro que vous avez codée est un peu étrange. Il générera plusieurs étapes de données qui écraseront toutes le même ensemble de données. Vous voudrez peut-être vous concentrer sur le fait de ne pas écrire d'abord le code de macro et de passer à celui-ci lorsque vous devez soumettre un code standard répétitif. Ecrire un bon code de macro signifie que vous devez penser en termes de "cela va-t-il générer un code source approprié et quel effet secondaire auront ces instructions de macro dans leur portée de résolution"

% DOIt. p>

% DO macro-variable = start % TO stop <% BY incrément >;

Instructions en langage texte et macro

<₹%END;

Arguments obligatoires

<^macro-variable

  • nomme une variable macro ou une expression de texte qui génère une macro Nom de variable. Sa valeur fonctionne comme un index qui détermine le nombre d'itérations de la boucle% DO. Si la variable macro spécifiée comme l'index n'existe pas, le processeur de macro le crée dans le table des symboles locaux.

  • Vous pouvez modifier la valeur du variable d'index pendant le traitement. Par exemple, en utilisant conditionnel traitement pour définir la valeur de la variable d'index au-delà de l'arrêt valeur lorsqu'une certaine condition est remplie met fin au traitement de la boucle.

< gagnantstartstop

  • spécifier des entiers ou des expressions de macro qui génèrent des entiers pour contrôler le nombre de fois la partie de la macro entre les Les instructions itératives% DO et% END sont traitées.

  • La première fois Le groupe% DO itère, la macro-variable est égale au début. Comme traitement continue, la valeur de la macro-variable change de la valeur de incrémenter jusqu'à ce que la valeur de la macro-variable soit en dehors de la plage de entiers inclus par start et stop.

< finalincrément

  • spécifie un entier (autre que 0) ou une expression de macro qui génère un entier à ajoutée à la valeur de la variable d'index à chaque itération du boucle. Par défaut, l'incrément est 1. L'incrément est évalué avant le première itération de la boucle. Par conséquent, vous ne pouvez pas le modifier car le boucle itère.


1 commentaires

Merci beaucoup Richard !!