BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
acordes
Rhodochrosite | Level 12

I want to delete the selected variable dynamically from the macro variable that was set at the beginning.

I put the code for context, it won't run like this. 

 

Imagine I start with the macro variable having the value : var1 var2 var3 var4

Now I select var2 from the glmselect and I want to withdraw it form the macro variable so that it becomes : var1 var3 var4.

 

 

data matched;
format _from _to $32. r2 8.3;
output;
run;

data matched;
set matched(obs=0);
run;

proc sql;
select name into :vary separated by ' ' 
from nok where type=1;
quit;

%put &vary.;


data _null_;
set WORK.NAMY_OK(obs=10 where=(type=1 and ^index(lowcase(name), 'var') ));
call execute ('
ods output ModelInfo=model SelectionSummary=selsum;
proc glmselect data=public.ttt ;
model ' || name || '  = &vary. / selection=stepwise( stop=1 ) noint;
run;

proc sql;
select tranwrd("&vary.", strip(EffectEntered),"") into :vary 
from WORK.SELSUM;
quit;


%put &vary.;

proc sql;
insert into matched(_from, _to, r2 )
select ' || quote(name) || ', strip(EffectEntered), RSquare 
from  WORK.SELSUM;
quit;');
run;

 

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User
DOSUBL instead of CALL EXECUTE which runs immediately.

View solution in original post

17 REPLIES 17
russt_sas
SAS Employee

You could use TRANWRD to replace the string you want to remove with a blank, for example:

 

%let list=var1 var2 var3 var4;
%let cnt=%sysfunc(countw(&list));
%macro test(remove);
%let newlist=%cmpres(%sysfunc(tranwrd(&list,&remove,%str())));
%put &newlist;
%mend test;

/* Pass in the string you want to remove */

%test(var2)

acordes
Rhodochrosite | Level 12

Thanks, I get the point, but I cannot adapt it to my needs.

 

I need the macro variable to be updated, not to create a new one. 

Once a variable get selected I want to hide from being selected again. 

 

 

russt_sas
SAS Employee

You do not have to create a new variable, that was just an example.  Here is the same code using the same variable:

 

%let list=var1 var2 var3 var4;
%let cnt=%sysfunc(countw(&list));
%macro test(remove);
%let list=%cmpres(%sysfunc(tranwrd(&list,&remove,%str())));
%put &list;
%mend test;
%test(var2)

acordes
Rhodochrosite | Level 12

No, it does not work:

 


data matched;
format _from _to $32. r2 8.3;
output;
run;

data matched;
set matched(obs=0);
run;

proc sql;
select name into :vary separated by ' ' 
from nok where type=1;
quit;

%put &vary.;

%macro test(remove);
%let vary=%cmpres(%sysfunc(tranwrd(&vary,&remove,%str())));
%put &vary;
%mend test;

data _null_;
set WORK.NAMY_OK(obs=10 where=(type=1 and ^index(lowcase(name), 'var') ));
call execute ('
ods output ModelInfo=model SelectionSummary=selsum;
proc glmselect data=public.ttt ;
model ' || name || '  = &vary. / selection=stepwise( stop=1 ) noint;
run;

proc sql;
select strip(EffectEntered) into :oks 
from WORK.SELSUM;
quit;


%test(&oks.);

proc sql;
insert into matched(_from, _to, r2 )
select ' || quote(name) || ', strip(EffectEntered), RSquare 
from  WORK.SELSUM;
quit;');
run;
Quentin
Super User

What does "doesn't work" mean?

 

There are some tricky timing issues with CALL EXECUTE when you use macro code.  You should try adding %NRSTR to mask the macro symbols until after CALL EXECUTE has generated the code.

 

Like:

 


data _null_ ;
  call execute(
    '%nrstr('
    || '%let vars=name sex height ;'
    || 'proc print data=sashelp.class ; var &vars ; run ;'
    || '%let vars=%sysfunc(transtrn(%str( )&vars%str( ),%str( height ),%str( ))) ;'
    || 'proc print data=sashelp.class ; var &vars ; run ;'
    || ')' 
  ) ;
run ;

 

BASUG is hosting free webinars Next up: Don Henderson presenting on using hash functions (not hash tables!) to segment data on June 12. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
Quentin
Super User

One potential gotcha I always forget is that despite the name, TRANWRD doesn't actually know about word boundaries.  So if the word you delete is a substring of another word, it will delete the substring as well.

 

1    %let vary=AAA AAABBB BBB CCC ;
2    %let vary=%sysfunc(tranwrd(&vary,BBB,)) ;
3    %put &=vary ;
VARY=AAA AAA    CCC

You can add delimiters to the ends of the list to work around this, perhaps with something ugly like:

1    %let vary=AAA AAABBB BBB CCC ;
2    %let vary=%sysfunc(transtrn(%str( )&vary%str( ),%str( BBB ),%str( ))) ;
3    %put &=vary ;
VARY=AAA AAABBB CCC
BASUG is hosting free webinars Next up: Don Henderson presenting on using hash functions (not hash tables!) to segment data on June 12. Register now at the Boston Area SAS Users Group event page: https://www.basug.org/events.
russt_sas
SAS Employee

Can you share what the NOK data set looks like?

acordes
Rhodochrosite | Level 12

here comes the code / idea applied on sashelp.cars.

 

I want to identify variables that despite come without label can be related to other known variables. 

We have this situation quite often, this ugly flat files that sometimes change the variable order or loose the variable names. 

 

data cars;
set sashelp.cars;
id=put(_n_, 4.);
keep id _numeric_;
run;

proc sql;
select name||"=var" || strip(put(monotonic(), 3.)) into :reny separated by ' ' 
from dictionary.columns where libname='WORK' and memname='CARS'
and name ne "id";
quit;

data unknown;
set cars;
rename &reny.;
run;

data unknown;
set unknown;
array numy(10) var1-var10;
var_rand=rand('integer', 1, 10);
if rand('uniform', 0, 1) le 0.05 then do;
numy(var_rand)= numy(var_rand)*0.9;
end;
drop var_rand;
run;

proc contents data=cars out=namy_ok;
run;

proc contents data=unknown out=nok;
run;

data together;
merge cars unknown;
by id;
run;


data matched;
format _from _to $32. r2 8.3;
output;
run;

data matched;
set matched(obs=0);
run;

proc sql;
select name into :vary separated by ' ' 
from nok where type=1;
quit;

%put &vary.;


data _null_;
set WORK.NAMY_OK(obs=10 where=(type=1 and ^index(lowcase(name), 'var') ));
call execute ('
ods output ModelInfo=model SelectionSummary=selsum;
proc glmselect data=together ;
model ' || name || '  = &vary. / selection=stepwise( stop=1 ) noint;
run;

proc sql;
select tranwrd("&vary.", strip(EffectEntered),"") into :vary 
from WORK.SELSUM;
quit;

%put &vary.;

proc sql;
insert into matched(_from, _to, r2 )
select ' || quote(name) || ', strip(EffectEntered), RSquare 
from  WORK.SELSUM;
quit;');
run;
acordes
Rhodochrosite | Level 12

after every iteration over proc glmselect I want to purge the selected variable from the list of candidates.

Tom
Super User Tom
Super User

@acordes wrote:

after every iteration over proc glmselect I want to purge the selected variable from the list of candidates.


I don't understand how CALL EXECUTE() would be involved in solving such a problem.

CALL EXECUTE() lets you stack up some code to run after the current step (the one that is running the CALL EXECUTE() statement) has finished running.

 

acordes
Rhodochrosite | Level 12
So what Do you propose instead?
I need to update and shorten the candidate list of variables by when they end up getting selected by glmselect.
russt_sas
SAS Employee

I am still not 100% sure what you need.

 

If you are wanting to run multiple glmselect on a different variable each time, what determines which variable we use and/or exclude?

 

If you had variables var1 var2 var3 var4, are you wanting to run the glmselect 4 times removing one of the variables each time?

Tom
Super User Tom
Super User

@acordes wrote:
So what Do you propose instead?
I need to update and shorten the candidate list of variables by when they end up getting selected by glmselect.

Are you trying to simulate a STEPWISE regression? Are you sure the PROC doesn't already support that?  Have you confirmed with a statistician that the approach is sensible?

 

Do you want to just loop thru the list and take 9 variables each time?  So create a macro with code like this to call your model with the N ways to eliminate one variable from a list of N variables.

%let list=A|B|C;
%do i=1 to %sysfunc(countw(&list,|));
  %let varlist=%sysfunc(tranwrd(|&list|,|%scan(&list,&i,|)|,|));
  %let varlist=%sysfunc(translate(&varlist,%str( ),|));
/*
run your model using the N-1 variables in &VARLIST
*/
%end;

If you want to start with a list of 10 variables and run some statistical test and then select one variable to remove and repeat until what?  There is just one variable left?  If then the loop might look more like:

%let list=A B C;
%do %while(%length(&list));
/*
run your model.
select the variable to eliminate into macro variable DROPVAR
*/
  %let list=%sysfunc(tranwrd(%str( &list ),%str( &dropvar ),%str( )));
%end;
acordes
Rhodochrosite | Level 12

I’ll give that a try. I don’t need the statistical waterproof, it’s meant as a trick to cluster one by one variables that supposed to measure the same whereas one group of variables is duly labeled and has meaningful names while the others stem from a flat file import where labels weren’t transmitted and variable names are like var1-var50.

Therefore I use the glmselect modeling each by each the known variables trying to find its sibling forcing a regression with stop criteria 1 and skipping an intercept term.

I would say it gives a good result but I’m struggling to update the unknown variables list.

 

 

Ready to join fellow brilliant minds for the SAS Hackathon?

Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.

Register today!
How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 17 replies
  • 1715 views
  • 6 likes
  • 5 in conversation