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

Hi SAS community

 

I have data over time for ~200 participants. For each participant, I want to fit the same model, but I have a different set of initial conditions for the PROC NLIN routine (derived by looking at data for each paritcipant). How do I get this to work (code below)? Any help really appreciate. I keep get error like this:

NOTE: DER.a not initialized or missing. It will be computed automatically.
NOTE: DER.b not initialized or missing. It will be computed automatically.
NOTE: DER.c not initialized or missing. It will be computed automatically.
NOTE: DER.d not initialized or missing. It will be computed automatically.
WARNING: Zero observations could be evaluated.
NOTE: The data set WORK.PARAMS_OUT_4 has 0 observations and 9 variables.

 

data initial_params;
set in.initial_params;
nf+1;
call symputx("last_nf",nf);
run;

data participant_data;
set in.participant_data;
run;

%macro fit;
%do j=1 %to &last_nf.;

data _null_; 
 	set initial_params;
 	where nf=&j;
 	call symputx("beta10",beta10);
	call symputx("beta20",beta20);
	call symputx("beta30",beta30);
call symputx("beta40".beta40); call symputx("participant",subject); run; proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out_&j.; where subject="&participant"; parameters a = &beta10. &beta20. = -3 c = &beta30. d = &beta40.; model response = a*exp(time/b) + c*time + d; run; %end; %mend; %fit;

suggesting what I do wrong would be very helpful to me!

1 ACCEPTED SOLUTION

Accepted Solutions
FreelanceReinh
Jade | Level 19

Hi @linlin87,

 

First of all, I see two syntax errors in your code which would prevent the PROC NLIN step from even producing the messages you show:

  1. The period between "beta40" and beta40 in the fourth CALL SYMPUTX of the DATA _NULL_ step must be a comma.
  2. Instead of &beta20. = -3 in the PARAMETERS statement I would rather expect something like b = &beta20. (or does macro variable BETA20 contain a variable name such as b?).

One situation in which the warning "Zero observations could be evaluated" would occur is that the WHERE condition subject="&participant" is not met for any observation of dataset PARTICIPANT_DATA. So, make sure that those character values match exactly.

 

But most importantly, I think you could both simplify your program and make it more robust if you used a single PROC NLIN step with a BY statement (by subject) instead of the macro, macro variables and the WHERE condition. Then you could name the dataset containing the subject-specific initial parameter values in the PDATA= option of the PARAMETERS statement. See the syntax and section "Assigning Starting Values from a SAS Data Set" in the PROC NLIN documentation.

 

Edit: Below is an example of what your PROC NLIN step could look like. Note the structure of the PDATA= dataset (which I named init_params).

 

/* Create test data for demonstration */

data temp;
input subject a b c d;
cards;
1  8 2 0.2  1
2  7 1 0.3 -1
;

proc transpose data=temp out=init_params(rename=(col1=estimate)) name=parameter;
by subject;
run;

data participant_data(drop=a--d);
set temp;
do time=1 to 5;
  response=a*exp(time/b) + c*time + d + rannor(1);
  output;
end;
run;

/* Use BY-group processing and the PDATA= option in PROC NLIN */

proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out;
by subject;
parameters / pdata=init_params;
model response = a*exp(time/b) + c*time + d;
run;

 

 

View solution in original post

3 REPLIES 3
FreelanceReinh
Jade | Level 19

Hi @linlin87,

 

First of all, I see two syntax errors in your code which would prevent the PROC NLIN step from even producing the messages you show:

  1. The period between "beta40" and beta40 in the fourth CALL SYMPUTX of the DATA _NULL_ step must be a comma.
  2. Instead of &beta20. = -3 in the PARAMETERS statement I would rather expect something like b = &beta20. (or does macro variable BETA20 contain a variable name such as b?).

One situation in which the warning "Zero observations could be evaluated" would occur is that the WHERE condition subject="&participant" is not met for any observation of dataset PARTICIPANT_DATA. So, make sure that those character values match exactly.

 

But most importantly, I think you could both simplify your program and make it more robust if you used a single PROC NLIN step with a BY statement (by subject) instead of the macro, macro variables and the WHERE condition. Then you could name the dataset containing the subject-specific initial parameter values in the PDATA= option of the PARAMETERS statement. See the syntax and section "Assigning Starting Values from a SAS Data Set" in the PROC NLIN documentation.

 

Edit: Below is an example of what your PROC NLIN step could look like. Note the structure of the PDATA= dataset (which I named init_params).

 

/* Create test data for demonstration */

data temp;
input subject a b c d;
cards;
1  8 2 0.2  1
2  7 1 0.3 -1
;

proc transpose data=temp out=init_params(rename=(col1=estimate)) name=parameter;
by subject;
run;

data participant_data(drop=a--d);
set temp;
do time=1 to 5;
  response=a*exp(time/b) + c*time + d + rannor(1);
  output;
end;
run;

/* Use BY-group processing and the PDATA= option in PROC NLIN */

proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out;
by subject;
parameters / pdata=init_params;
model response = a*exp(time/b) + c*time + d;
run;

 

 

linlin87
Quartz | Level 8

Thank you @FreelanceReinh !!

One more questions for you. Now I have this

 

proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out;
by subject;
parameters / pdata=init_params;
model response = a*exp(time/b) + c*time + d;
run;

but actually I need that a+d = value. So:

proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out;
by subject;
parameters / pdata=init_params;
bounds d+a = value;
model response = a*exp(time/b) + c*time + d;
run;

Note that value is different for each SUBJECT. How do I do?

FreelanceReinh
Jade | Level 19

You're welcome.

 

I think the BOUNDS statement is more suitable for constraints in the form of inequalities about the parameters. Given that all these numbers are non-integers, an exact equality such as d+a=value would be a risky requirement anyway. (Note that, e.g., 0.1+0.2 ne 0.3 in Windows SAS due to rounding errors in the binary system.) Also, the BOUNDS statement, unlike the PARAMETERS statement, does not allow for varying values coming from a dataset. There is a different procedure, PROC HPNLMOD, which offers a RESTRICT statement where you could specify your linear constraint. But I have never used PROC HPNLMOD before today, so let's stay with PROC NLIN.

 

In PROC NLIN it's probably better to implement the constraint d+a=value in the model equation. You have two options for that: Either replace d with value-a, or replace a with value-d. Let's follow the first approach, i.e., eliminate parameter d in the model equation and introduce value as a new variable (not parameter) in the input dataset participant_data.

 

Here is the example from my earlier post, with the new constraint implemented. Changes are highlighted in blue.

/* Create test data for demonstration */

data temp;
input subject a b c value; /* parameter d has been eliminated by the constraint d+a=value */
cards;
1  8 2 0.2 9
2  7 1 0.3 6
;

proc transpose data=temp(drop=value) out=init_params(rename=(col1=estimate)) name=parameter;
by subject;
run;

data participant_data(drop=a--c);
set temp;
do time=1 to 5;
  response=a*exp(time/b) + c*time + value - a + rannor(1);
  output;
end;
run;

/* Use BY-group processing and the PDATA= option in PROC NLIN */

proc nlin data = participant_data g4 plots = fit maxiter = 50 outest = params_out;
by subject;
parameters / pdata=init_params;
model response = a*exp(time/b) + c*time + value - a;
run;

 

As you can see in dataset participant_data, variable value is a subject-dependent constant over time. Parameters a, b, c are estimated, starting with (unchanged) subject-specific initial values from dataset init_params, as before. For each subject, you could use the estimate for parameter a computed by PROC NLIN and the known value of variable value to compute d = value - a, if needed:

data est(drop=_:);
set params_out;
where _type_='FINAL';
run;

data values;
set participant_data(keep=subject value);
by subject;
if first.subject;
run;

data want;
merge values est;
by subject;
d=value-a;
run;

 

Obviously, the estimates will satisfy the constraint a+d = value, possibly up to tiny rounding differences like 1E-16 as in this example:

138   data _null_;
139   d=0.9-0.3;
140   if 0.3+d ne 0.9 then put 'Surprised?';
141   delta=0.3+d-0.9;
142   put delta=;
143   run;

Surprised?
delta=1.110223E-16

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!
Mastering the WHERE Clause in PROC SQL

SAS' Charu Shankar shares her PROC SQL expertise by showing you how to master the WHERE clause using real winter weather data.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 3 replies
  • 774 views
  • 1 like
  • 2 in conversation