SAS IML use of Mattrib with Macro (symget) in a lo

2019-08-17 05:20发布

In an IML proc I have several martices and several vectors with the names of columns:

proc IML;
    mydata1 = {1 2 3, 2 3 4};
    mydata2 = {1 2, 2 3};
    names1 = {'red'  'green' 'blue'};
    names2 = {'black' 'white'};

To assign column names to columns in matrices one can copypaste the mattrib statement enough times:

    /*  mattrib mydata1 colname=names1;*/
    /*  mattrib mydata2 colname=names2;*/

However, in my case the number of matrices is defined at execution, thus a do loop is needed. The following code

    varNumb=2;
    do idx=1 to varNumb;
        call symputx ('mydataX', cat('mydata',idx));
        call symputx ('namesX', cat('names',idx));
        mattrib (symget('mydataX')) colname=(symget('namesX'));
    end;

    print (mydata1[,'red']) (mydata2[,'white']);
quit;

however produces the "Expecting a name" error on the first symget.

Similar question Loop over names in SAS-IML? offers the macro workaround with symget, what produces an error here.

What is the correct way of using mattrib with symget? Is there other way of making a variable from a string than macro?

Any help would be appreciated.

Thanks, Alex


EDIT1

The problem is in the symget function. The &-sign resolves the name of the matrix contained in the macro variable, the symget only returns the name of the macro.

proc IML;
    mydata1 = {1 2 3};
    call symputx ('mydataX', 'mydata1');
    mydataNew = (symget('mydataX'));

    print (&mydataX);
    print (symget("mydataX"));
    print mydataNew;
quit;

results in

mydata1 :   
1 2 3 

mydata1 

mydataNew :  
mydata1 

Any ideas?


EDIT2

Function value solves the symget problem in EDIT1

    mydataNew = value(symget('mydataX'));
    print (&mydataX);
    print (value(symget("mydataX")));
    print mydataNew;

The mattrib issue but persists.


SOLVED

Thanks Rick, you have opened my eyes to CALL EXECUTE() statement.

1条回答
啃猪蹄的小仙女
2楼-- · 2019-08-17 05:59

When you use CALL SYMPUTX, you should not use quotes for the second argument. Your statement

call symputx ('mydataX', 'mydata1');

assigns the string 'mydata1' to the macro variable.

In general, trying to use macro variables in SAS/IML loops often results in complicated code. See the article Macros and loops in the SAS/IML language for an indication of the issues caused by trying to combine a macro preprocessor with an interactive language. Because the MATTRIB statement expects a literal value for the matrix name, I recomend that you use CALL EXECUTE rather than macro substitution to execute the MATTRIB statement.

You are also having problems because a macro variable is always a scalar string, whereas the column name is a vector of strings. Use the ROWCAT function to concatenate the vector of names into a single string.

The following statements accomplish your objective without using macro variables:

/* Use CALL EXECUTE to set matrix attributes dynamically.
   Requires that matrixName and varNames be defined at main scope */
start SetMattrib;
   cmd =  "mattrib " + matrixName + " colname={" + varNames + "};";
   *print cmd;    /* for debugging */
   call execute(cmd);
finish;

varNumb=2;
do idx=1 to varNumb;
    matrixName = cat('mydata',idx);
    varNames = rowcat( value(cat('names',idx)) + " " );
    run SetMattrib;
end;
查看更多
登录 后发表回答