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

When I enter the mycas.camp_append data step I only have macro variables defined for one of the 6 arrays. These depend on the choices the user makes through an html prompt. The user selects one out of 6 alternatives. But having the other 5 choices not initialized this gives an error at this data step.

 

I circumvent the problem by assigning dummy values in a data _null_ step to all macro variables that are not used. It's a if-then logic. It works but it feels very complicated. 

 

data _null_;

if &prodStmt="value1" then do;
call symputx("next5_disc_cred1", "temp|temp");
call symputx("next5_disc_cred2", "temp|temp");
call symputx("next5_disc_cred3", "temp|temp");
call symputx("next5_disc_cred4", "temp|temp");
call symputx("next5_disc_cred5", "temp|temp");
call symputx("cpc5_disc_cred1", "temp|temp");
call symputx("cpc5_disc_cred2", "temp|temp");
call symputx("cpc5_disc_cred3", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");
call symputx("cpc5_disc_cred5", "temp|temp");

call symputx("cpc4_disc_cred1", "temp|temp");
call symputx("cpc4_disc_cred2", "temp|temp");
call symputx("cpc4_disc_cred3", "temp|temp");
call symputx("cpc4_disc_cred4", "temp|temp");

call symputx("lin5_disc_cred1", "temp|temp");
call symputx("lin5_disc_cred2", "temp|temp");
call symputx("lin5_disc_cred3", "temp|temp");
call symputx("lin5_disc_cred4", "temp|temp");
call symputx("lin5_disc_cred5", "temp|temp");

call symputx("lin4_disc_cred1", "temp|temp");
call symputx("lin4_disc_cred2", "temp|temp");
call symputx("lin4_disc_cred3", "temp|temp");
call symputx("lin4_disc_cred4", "temp|temp");

end;

if &prodStmt="value2" then do;
call symputx("next4_disc_cred1", "temp|temp");
call symputx("next4_disc_cred2", "temp|temp");
call symputx("next4_disc_cred3", "temp|temp");
call symputx("next4_disc_cred4", "temp|temp");

call symputx("cpc5_disc_cred1", "temp|temp");
call symputx("cpc5_disc_cred2", "temp|temp");
call symputx("cpc5_disc_cred3", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");
call symputx("cpc5_disc_cred5", "temp|temp");

call symputx("cpc4_disc_cred1", "temp|temp");
call symputx("cpc4_disc_cred2", "temp|temp");
call symputx("cpc4_disc_cred3", "temp|temp");
call symputx("cpc4_disc_cred4", "temp|temp");

call symputx("lin5_disc_cred1", "temp|temp");
call symputx("lin5_disc_cred2", "temp|temp");
call symputx("lin5_disc_cred3", "temp|temp");
call symputx("lin5_disc_cred4", "temp|temp");
call symputx("lin5_disc_cred5", "temp|temp");

call symputx("lin4_disc_cred1", "temp|temp");
call symputx("lin4_disc_cred2", "temp|temp");
call symputx("lin4_disc_cred3", "temp|temp");
call symputx("lin4_disc_cred4", "temp|temp");

end;

if &prodStmt="value3" then do;
call symputx("next4_disc_cred1", "temp|temp");
call symputx("next4_disc_cred2", "temp|temp");
call symputx("next4_disc_cred3", "temp|temp");
call symputx("next4_disc_cred4", "temp|temp");

call symputx("next5_disc_cred1", "temp|temp");
call symputx("next5_disc_cred2", "temp|temp");
call symputx("next5_disc_cred3", "temp|temp");
call symputx("next5_disc_cred4", "temp|temp");
call symputx("next5_disc_cred5", "temp|temp");

call symputx("cpc5_disc_cred1", "temp|temp");
call symputx("cpc5_disc_cred2", "temp|temp");
call symputx("cpc5_disc_cred3", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");

call symputx("lin5_disc_cred1", "temp|temp");
call symputx("lin5_disc_cred2", "temp|temp");
call symputx("lin5_disc_cred3", "temp|temp");
call symputx("lin5_disc_cred4", "temp|temp");
call symputx("lin5_disc_cred5", "temp|temp");

call symputx("lin4_disc_cred1", "temp|temp");
call symputx("lin4_disc_cred2", "temp|temp");
call symputx("lin4_disc_cred3", "temp|temp");
call symputx("lin4_disc_cred4", "temp|temp");

end;

if &prodStmt="value4" then do;
call symputx("next4_disc_cred1", "temp|temp");
call symputx("next4_disc_cred2", "temp|temp");
call symputx("next4_disc_cred3", "temp|temp");
call symputx("next4_disc_cred4", "temp|temp");

call symputx("next5_disc_cred1", "temp|temp");
call symputx("next5_disc_cred2", "temp|temp");
call symputx("next5_disc_cred3", "temp|temp");
call symputx("next5_disc_cred4", "temp|temp");
call symputx("next5_disc_cred5", "temp|temp");

call symputx("cpc4_disc_cred1", "temp|temp");
call symputx("cpc4_disc_cred2", "temp|temp");
call symputx("cpc4_disc_cred3", "temp|temp");
call symputx("cpc4_disc_cred4", "temp|temp");

call symputx("lin5_disc_cred1", "temp|temp");
call symputx("lin5_disc_cred2", "temp|temp");
call symputx("lin5_disc_cred3", "temp|temp");
call symputx("lin5_disc_cred4", "temp|temp");
call symputx("lin5_disc_cred5", "temp|temp");

call symputx("lin4_disc_cred1", "temp|temp");
call symputx("lin4_disc_cred2", "temp|temp");
call symputx("lin4_disc_cred3", "temp|temp");
call symputx("lin4_disc_cred4", "temp|temp");

end;

if &prodStmt="value5" then do;
call symputx("next4_disc_cred1", "temp|temp");
call symputx("next4_disc_cred2", "temp|temp");
call symputx("next4_disc_cred3", "temp|temp");
call symputx("next4_disc_cred4", "temp|temp");

call symputx("next5_disc_cred1", "temp|temp");
call symputx("next5_disc_cred2", "temp|temp");
call symputx("next5_disc_cred3", "temp|temp");
call symputx("next5_disc_cred4", "temp|temp");
call symputx("next5_disc_cred5", "temp|temp");

call symputx("cpc5_disc_cred1", "temp|temp");
call symputx("cpc5_disc_cred2", "temp|temp");
call symputx("cpc5_disc_cred3", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");

call symputx("lin5_disc_cred1", "temp|temp");
call symputx("lin5_disc_cred2", "temp|temp");
call symputx("lin5_disc_cred3", "temp|temp");
call symputx("lin5_disc_cred4", "temp|temp");
call symputx("lin5_disc_cred5", "temp|temp");

call symputx("cpc4_disc_cred1", "temp|temp");
call symputx("cpc4_disc_cred2", "temp|temp");
call symputx("cpc4_disc_cred3", "temp|temp");
call symputx("cpc4_disc_cred4", "temp|temp");

end;

if &prodStmt="value6" then do;
call symputx("next4_disc_cred1", "temp|temp");
call symputx("next4_disc_cred2", "temp|temp");
call symputx("next4_disc_cred3", "temp|temp");
call symputx("next4_disc_cred4", "temp|temp");

call symputx("next5_disc_cred1", "temp|temp");
call symputx("next5_disc_cred2", "temp|temp");
call symputx("next5_disc_cred3", "temp|temp");
call symputx("next5_disc_cred4", "temp|temp");
call symputx("next5_disc_cred5", "temp|temp");

call symputx("cpc5_disc_cred1", "temp|temp");
call symputx("cpc5_disc_cred2", "temp|temp");
call symputx("cpc5_disc_cred3", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");
call symputx("cpc5_disc_cred4", "temp|temp");

call symputx("lin4_disc_cred1", "temp|temp");
call symputx("lin4_disc_cred2", "temp|temp");
call symputx("lin4_disc_cred3", "temp|temp");
call symputx("lin4_disc_cred4", "temp|temp");


call symputx("cpc4_disc_cred1", "temp|temp");
call symputx("cpc4_disc_cred2", "temp|temp");
call symputx("cpc4_disc_cred3", "temp|temp");
call symputx("cpc4_disc_cred4", "temp|temp");

end;

run;




data mycas.camp_append;
array nxt4 (4) $50. _temporary_ ("&next4_disc_cred1." "&next4_disc_cred2." "&next4_disc_cred3." "&next4_disc_cred4.");
array nxt5 (5) $50. _temporary_ ("&next5_disc_cred1." "&next5_disc_cred2." "&next5_disc_cred3." "&next5_disc_cred4." "&next5_disc_cred5.");
array cp4 (4) $50. _temporary_ ("&cpc4_disc_cred1." "&cpc4_disc_cred2." "&cpc4_disc_cred3." "&cpc4_disc_cred4.");
array cp5 (5) $50. _temporary_ ("&cpc5_disc_cred1." "&cpc5_disc_cred2." "&cpc5_disc_cred3." "&cpc5_disc_cred4." "&cpc5_disc_cred5.");
array li4 (4) $50. _temporary_ ("&lin4_disc_cred1." "&lin4_disc_cred2." "&lin4_disc_cred3." "&lin4_disc_cred4.");
array li5 (5) $50. _temporary_ ("&lin5_disc_cred1." "&lin5_disc_cred2." "&lin5_disc_cred3." "&lin5_disc_cred4." "&lin5_disc_cred5.");

array news (35) 
tramo1 t1_disc36 t1_disc48 t1_disc60 t1_disc72 t1_disc84 t1_disc96 
tramo2 t2_disc36 t2_disc48 t2_disc60 t2_disc72 t2_disc84 t2_disc96 
tramo3 t3_disc36 t3_disc48 t3_disc60 t3_disc72 t3_disc84 t3_disc96 
tramo4 t4_disc36 t4_disc48 t4_disc60 t4_disc72 t4_disc84 t4_disc96 
tramo5 t5_disc36 t5_disc48 t5_disc60 t5_disc72 t5_disc84 t5_disc96 
;

if &prodStmt="value1" then do;
do i=1 to dim(nxt4);
mult=(i-1)*4;
multi=(i-1);
do j=1 to 4;
news(mult+j + multi*3)=input(scan(nxt4(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

if &prodStmt="value2" then do;
do i=1 to dim(nxt5);
mult=(i-1)*4;
multi=(i-1);
do j=1 to 4;
news(mult+j + multi*3)=input(scan(nxt5(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

if &prodStmt="value3" then do;
do i=1 to dim(cp4);
mult=(i-1)*4;
multi=(i-1);
do j=1 to 3;
news(mult+j + multi*3)=input(scan(cp4(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

if &prodStmt="value4" then do;
do i=1 to dim(cp5);
mult=(i-1)*4;
multi=(i-1);
do j=1 to 3;
news(mult+j + multi*3)=input(scan(cp5(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

if &prodStmt="value5" then do;
do i=1 to dim(li4);
mult=(i-1)*7;
multi=(i-1)*0;
do j=1 to 7;
news(mult+j + multi*3)=input(scan(li4(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

if &prodStmt="value6" then do;
do i=1 to dim(li5);
mult=(i-1)*7;
multi=(i-1)*0;
do j=1 to 7;
news(mult+j + multi*3)=input(scan(li5(i), j, '0123456789', 'k'), best12.);
end;
end;
end;

drop i j mult multi;

run;
1 ACCEPTED SOLUTION

Accepted Solutions
Tom
Super User Tom
Super User

Not sure I follow all of your code. Let's just look at the most complex of those items on your screen shot.

image.png

So let's say that question on your form was named CREDIT.  Then the user interface will generate these macro variables for the values shown in that picture.

%let credit0=4;
%let credit=9000=1500|2000|2300;
%let credit1=9000=1500|2000|2300;
%let credit2=11000=1800|2200|2500;
%let credit3=1500=2000|2700|3000;
%let credit4=18000=2400|3100|3500;

The dataset in that last photograph does not look very useful for anything.  A taller structure with fewer variables would probably work better for most purposes.

data want;
  length count order tramo index months disc 8 string $100;
  if not symexist('credit') then count=0;
  else do; 
     count=1;
     if not symexist('credit1') then call symputx('credit1',symget('credit'));
  end;
  if symexist('credit0') then count=symgetn('credit0');
  do order=1 to count;
    string=symget(cats('credit',order));
    tramo=input(scan(string,1,'='),32.);
    string=scan(string,2,'=');
    months=24 ;
    do index=1 to countw(string,'|');
      months+12;
      disc=input(scan(string,index,'|'),32.);
      output;
    end;
  end;
  drop string;
run;

Results

Obs    count    order    tramo    index    months    disc

  1      4        1       9000      1        36      1500
  2      4        1       9000      2        48      2000
  3      4        1       9000      3        60      2300
  4      4        2      11000      1        36      1800
  5      4        2      11000      2        48      2200
  6      4        2      11000      3        60      2500
  7      4        3       1500      1        36      2000
  8      4        3       1500      2        48      2700
  9      4        3       1500      3        60      3000
 10      4        4      18000      1        36      2400
 11      4        4      18000      2        48      3100
 12      4        4      18000      3        60      3500

View solution in original post

5 REPLIES 5
Kurt_Bremser
Super User

What (exactly!) is contained in the macro variable prodstmt? I ask because of your use of quotes in the conditions.

 

Next, you just use macro %IF %THEN %DO %END blocks to conditionally submit the array definitions (all using the same array name), and do only one data step loop over the array.

Tom
Super User Tom
Super User

I don't understand what you are trying to do.

 

Sounds like you are using some user interface that will create global macro variables to store user choices in the interface?  Is the normal SAS utility that create a COUNT macro variable and then series of macro variables with a numeric suffix?  Like in this discussion?  https://communities.sas.com/t5/SAS-Stored-Processes/Multiple-selections-in-a-stored-process/td-p/141...

 

Are you trying to convert those into data instead of macro variables?

Here is a data step that will loop over a series of prefixes for macro variables and check.  When the macro variable does not exist it is set to your temp|temp string.  

I set the upper bound to 5 since that appeared to be what you were using.

%let xxx=x1;
%let xxx1=x1;
%let xxx2=x2;
%let xxx0=2;
%let yyy=y1;

data from_gmv ;
  length prefix $31 count index 8 mvar $32 value $50 ;
  do prefix='xxx','yyy','zzz';
    if not symexist(prefix) then count=0;
    else count=1;
    if symexist(cats(prefix,'0')) then count=symgetn(cats(prefix,'0'));
    if count=1 then call symputx(cats(prefix,'1'),symget(prefix),'g');
    do index=1 to 5;
      mvar=cats(prefix,index);
      value='temp|temp';
      if symexist(mvar) then value=symget(mvar);
      else call symputx(mvar,value,'g');
      output;
    end;
  end;
run;

proc print;
run;

It also retrieves the existing macro variable values into a dataset so that you can avoid using the macro variables and instead just use the dataset.

Obs    prefix    count    index    mvar    value

  1     xxx        2        1      xxx1    x1
  2     xxx        2        2      xxx2    x2
  3     xxx        2        3      xxx3    temp|temp
  4     xxx        2        4      xxx4    temp|temp
  5     xxx        2        5      xxx5    temp|temp
  6     yyy        1        1      yyy1    y1
  7     yyy        1        2      yyy2    temp|temp
  8     yyy        1        3      yyy3    temp|temp
  9     yyy        1        4      yyy4    temp|temp
 10     yyy        1        5      yyy5    temp|temp
 11     zzz        0        1      zzz1    temp|temp
 12     zzz        0        2      zzz2    temp|temp
 13     zzz        0        3      zzz3    temp|temp
 14     zzz        0        4      zzz4    temp|temp
 15     zzz        0        5      zzz5    temp|temp
acordes
Rhodochrosite | Level 12

As I mentioned the hard-coded data _null_ works for me. I'll try your proposal and KurtBremser's as well and give you feedback.

 

It's a job using prompts. The context are financing campaigns for cars. 

The user can choose the product and as every product has its own contract terms (36,48,60 months for "Next") and 36 to 96 by 12 for "Lineal" for which the user needs to provide discounts and credit entry levels (another user's choice, 4 or 5 credit thresholds). The more credit the final customer takes and the longer he pays off the higher discount he gets, that's the reasoning. 

That makes in my case 3products X 2thresholds=6 values in the combobox. 

The discount scheme for each credit threshold is controlled via a validationtext with regex. 

 

When submitting the form I get to the job's code. 

I convert these thresholds and discunts into variables because the final objective is to apply scoring code from a gradient boosting that had learnt how car model, and thresholds and discounts explain what the market values ("given that campaign 40% fall into 36 months, 38% into 48 months and 22% into 60 months X thrhesolds). At the end you see the table that has nearly all the variables the scoring code expects. 

 

 

 

 

ok1.pngok.png

 

ok2.png

Tom
Super User Tom
Super User

Not sure I follow all of your code. Let's just look at the most complex of those items on your screen shot.

image.png

So let's say that question on your form was named CREDIT.  Then the user interface will generate these macro variables for the values shown in that picture.

%let credit0=4;
%let credit=9000=1500|2000|2300;
%let credit1=9000=1500|2000|2300;
%let credit2=11000=1800|2200|2500;
%let credit3=1500=2000|2700|3000;
%let credit4=18000=2400|3100|3500;

The dataset in that last photograph does not look very useful for anything.  A taller structure with fewer variables would probably work better for most purposes.

data want;
  length count order tramo index months disc 8 string $100;
  if not symexist('credit') then count=0;
  else do; 
     count=1;
     if not symexist('credit1') then call symputx('credit1',symget('credit'));
  end;
  if symexist('credit0') then count=symgetn('credit0');
  do order=1 to count;
    string=symget(cats('credit',order));
    tramo=input(scan(string,1,'='),32.);
    string=scan(string,2,'=');
    months=24 ;
    do index=1 to countw(string,'|');
      months+12;
      disc=input(scan(string,index,'|'),32.);
      output;
    end;
  end;
  drop string;
run;

Results

Obs    count    order    tramo    index    months    disc

  1      4        1       9000      1        36      1500
  2      4        1       9000      2        48      2000
  3      4        1       9000      3        60      2300
  4      4        2      11000      1        36      1800
  5      4        2      11000      2        48      2200
  6      4        2      11000      3        60      2500
  7      4        3       1500      1        36      2000
  8      4        3       1500      2        48      2700
  9      4        3       1500      3        60      3000
 10      4        4      18000      1        36      2400
 11      4        4      18000      2        48      3100
 12      4        4      18000      3        60      3500
acordes
Rhodochrosite | Level 12

ok, the technique is clear. 

thanks. 

 

I need the data set in wide format because de the variable t1_disc1 would mean in the context of the next product "36 month's discount having signed a credit above 9000 euros". 

I ran the algorithm with these columns plus car brand, model, interest rate, product, listprice...

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

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
  • 5 replies
  • 403 views
  • 2 likes
  • 3 in conversation