<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Help with Restricted Cubic Splines : Code Optimization and Graphical Output in Statistical Procedures</title>
    <link>https://communities.sas.com/t5/Statistical-Procedures/Help-with-Restricted-Cubic-Splines-Code-Optimization-and/m-p/968163#M48653</link>
    <description>&lt;P&gt;I don't know about "correct" but this certainly looks to be "fit for purpose." When you say optimize, I have to assume you mean "reduce how long it takes to generate results." That is going to depend on the amount of input data you have. As far as programming, I am not a good resource. The one thing I might suggest is using high performance versions of LOGISTIC and GLMSELECT (=HPLOGISTIC and =HPGENSELECT) to see if multi-threading speeds things up.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;SteveDenham&lt;/P&gt;</description>
    <pubDate>Wed, 04 Jun 2025 16:37:50 GMT</pubDate>
    <dc:creator>SteveDenham</dc:creator>
    <dc:date>2025-06-04T16:37:50Z</dc:date>
    <item>
      <title>Help with Restricted Cubic Splines : Code Optimization and Graphical Output</title>
      <link>https://communities.sas.com/t5/Statistical-Procedures/Help-with-Restricted-Cubic-Splines-Code-Optimization-and/m-p/968110#M48648</link>
      <description>&lt;P&gt;Hello, SAS experts&lt;/P&gt;&lt;P&gt;I am working on Restricted Cubic Splines&amp;nbsp; analysies and have written SAS code for both the continuous outcome and the binary outcome. I have included detailed comments in the code and have accounted for covarites. I have also attached the resulting plots and output tables, as well as a sample of the original dataset for reference.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Could you please review the the code, along with the generated graphs and results, and let me know if they are correct? I would greatly appreciate any suggestions for optimization.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thank you very much for your help!&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;/*A. Logistic RCS – Individual-level binary Y (poly) applied directly to raw data without prior aggregation*/
/* STEP 1: Rename MO and poly in RCS.poly to X and Y, and keep necessary covariates */
data poly;
   set RCS.poly;
   X = MO;       /* Month 1–12 */
   Y = poly;     /* Binary 0/1 */
   keep ID X Y CITY COUNT_gr;
run;

/* STEP 2: Sort by X (1–12) (needed for BY X if used for plotting) */
proc sort data=poly;
   by X;
run;

/* STEP 3: Fit logistic RCS on individual-level binary Y, adjusting for CITY and COUNT_gr */
title;
ods select ParameterEstimates SplineKnots;
proc logistic data=poly;
   /* Apply natural cubic spline on month X; knot locations can be adjusted */
   effect spl = spline(X /
                       details naturalcubic 
                       basis=tpf(noint)
                       knotmethod=percentilelist(5 27.5 50 72.5 95)  /* Example with 5 knots */
                      );
   /* Y(event='1') = spline(X) + covariates */
   model Y(event='1') = spl CITY COUNT_gr;
   /* Save each individual's predicted probability to PredProb */
   output out=LogitPred (keep=ID X Y CITY COUNT_gr PredProb) p=PredProb;
   title "Logistic RCS Model (Individual-level Binary Y)";
run;

/* STEP 4: Compute monthly average predicted probability by averaging individual-level PredProb by X */
proc means data=LogitPred noprint;
   by X;
   var PredProb;
   output out=AvgPred (drop=_TYPE_ _FREQ_) mean=MeanProb;
run;

/* STEP 5: Plot the RCS curve using 12 monthly average PredProb */
title;  
ods graphics / antialiasmax=500000;
title "Individual-level Logistic RCS: Monthly Avg Predicted Probability of poly";
proc sgplot data=AvgPred noautolegend;
   series  x=X        y=MeanProb  / lineattrs=(thickness=2 color=blue);
   scatter x=X        y=MeanProb  / markerattrs=(symbol=circlefilled size=4pt color=red);
   xaxis values=(1 to 12 by 1) label="Month (MO)";
   yaxis label="Average Predicted Probability of poly=1";
run;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;&lt;SPAN&gt;Dataset&lt;/SPAN&gt;：&lt;SPAN&gt;poly&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_0-1749036424357.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107565i2B5439C88856668F/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_0-1749036424357.png" alt="tina_ting_0-1749036424357.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Dataset&lt;/SPAN&gt;：&lt;SPAN&gt;LogitPred&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_1-1749036440256.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107566i035A51BE9B17DD23/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_1-1749036440256.png" alt="tina_ting_1-1749036440256.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Dataset&lt;/SPAN&gt;：&lt;SPAN&gt;AvgPred&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_2-1749036450093.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107567iB2B0CD9F35EE3147/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_2-1749036450093.png" alt="tina_ting_2-1749036450093.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_3-1749036463086.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107568i7920E79DD3F09307/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_3-1749036463086.png" alt="tina_ting_3-1749036463086.png" /&gt;&lt;/span&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_4-1749036465911.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107569iC4236FA54233F05A/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_4-1749036465911.png" alt="tina_ting_4-1749036465911.png" /&gt;&lt;/span&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_5-1749036469468.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107570iFADF0794C56C66AF/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_5-1749036469468.png" alt="tina_ting_5-1749036469468.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt;/* B. Individual level: continuous sum*/
/* sum: Cost_opd */
/*STEP 1: Rename MO and cost in RCS.cost to X and Y, and keep covariates */
data cost_ind;
   set RCS.cost;
   X = MO;           /* Month 1–12 */
   Y = cost;         /* Continuous dependent variable */
   /* If cost has missing values and you want to delete them first, uncomment the next line */
   /* if missing(Y) then delete; */
   keep ID X Y CITY COUNT_gr;
run;

proc sort data=cost_ind;
   by X;
run;

/* STEP 2: Perform RCS on individual-level data (continuous Y = cost), adjusting for CITY and COUNT_gr */
title;  
ods select ParameterEstimates SplineKnots;
proc glmselect data=cost_ind;
   /* Define a natural cubic spline on X; example with 5 knots: roughly at X=1, 4, 6, 9, 12 */
   effect spl = spline(
                 X /
                 details naturalcubic
                 basis=tpf(noint)
                 knotmethod=percentilelist(5 27.5 50 72.5 95)
               );
   /* Include spline(X), CITY, and COUNT_gr in the model */
   model Y = spl CITY COUNT_gr / selection=none;
   /* Save each individual’s predicted value to FitCost in cost_pred */
   output out=cost_pred predicted=FitCost;
run;

/*********** STEP 3: Check whether cost_pred contains FitCost ***********/
proc print data=cost_pred(obs=20);
   var ID X Y CITY COUNT_gr FitCost;
   title "Check cost_pred (first 20 observations)";
run;

proc means data=cost_pred n nmiss min max mean;
   var FitCost Y;
   title "Check FitCost (predicted) and Y (actual)";
run;

/*********** STEP 4A: Aggregate individual-level predicted values by month X using SUM ***********/
proc means data=cost_pred noprint;
   by X;  
   var FitCost;
   output out=MonthlyFit (drop=_TYPE_ _FREQ_) 
          sum=SumFitCost;   /* Use sum instead of mean */
run;

proc print data=MonthlyFit;
   title "Sum of fitted cost for each month (X)";
   var X SumFitCost;
run;

/*********** STEP 4B: Plot – Use 12 months of summed predicted values to draw RCS curve ***********/
title;  
ods graphics / antialiasmax=500000;
title "Individual-Level RCS: Monthly Sum of Fitted Cost by MO";
proc sgplot data=MonthlyFit noautolegend;
   series  x=X         y=SumFitCost / lineattrs=(thickness=2 color=blue);
   scatter x=X         y=SumFitCost / markerattrs=(symbol=circlefilled size=4pt color=red);
   xaxis values=(1 to 12 by 1) label="Month (MO)";
   yaxis label="Sum of Fitted Cost";
run;
ods graphics off;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Dataset：cost_ind&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_6-1749036525366.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107571i2BE3AC87ED731AAB/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_6-1749036525366.png" alt="tina_ting_6-1749036525366.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Dataset&lt;/SPAN&gt;：&lt;SPAN&gt;cost_pred&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_7-1749036535181.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107572iA0BA351148CA504C/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_7-1749036535181.png" alt="tina_ting_7-1749036535181.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;SPAN&gt;Dataset&lt;/SPAN&gt;：&lt;SPAN&gt;MonthlyFit&lt;/SPAN&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_8-1749036546854.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107573iDB54A73EE0FCE5F6/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_8-1749036546854.png" alt="tina_ting_8-1749036546854.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_9-1749036551891.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107574iEF7095F42E6997C7/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_9-1749036551891.png" alt="tina_ting_9-1749036551891.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_10-1749036556050.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107575i20E1B635B9A5780D/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_10-1749036556050.png" alt="tina_ting_10-1749036556050.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_11-1749036560589.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107576iA5B9E51007B22203/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_11-1749036560589.png" alt="tina_ting_11-1749036560589.png" /&gt;&lt;/span&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_12-1749036564183.png" style="width: 200px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107577i4654974E7DF7A6D7/image-size/small?v=v2&amp;amp;px=200" role="button" title="tina_ting_12-1749036564183.png" alt="tina_ting_12-1749036564183.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="tina_ting_13-1749036567913.png" style="width: 400px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/107578iE43AF82981F1E46B/image-size/medium?v=v2&amp;amp;px=400" role="button" title="tina_ting_13-1749036567913.png" alt="tina_ting_13-1749036567913.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 04 Jun 2025 11:32:45 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Statistical-Procedures/Help-with-Restricted-Cubic-Splines-Code-Optimization-and/m-p/968110#M48648</guid>
      <dc:creator>tina_ting</dc:creator>
      <dc:date>2025-06-04T11:32:45Z</dc:date>
    </item>
    <item>
      <title>Re: Help with Restricted Cubic Splines : Code Optimization and Graphical Output</title>
      <link>https://communities.sas.com/t5/Statistical-Procedures/Help-with-Restricted-Cubic-Splines-Code-Optimization-and/m-p/968163#M48653</link>
      <description>&lt;P&gt;I don't know about "correct" but this certainly looks to be "fit for purpose." When you say optimize, I have to assume you mean "reduce how long it takes to generate results." That is going to depend on the amount of input data you have. As far as programming, I am not a good resource. The one thing I might suggest is using high performance versions of LOGISTIC and GLMSELECT (=HPLOGISTIC and =HPGENSELECT) to see if multi-threading speeds things up.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;SteveDenham&lt;/P&gt;</description>
      <pubDate>Wed, 04 Jun 2025 16:37:50 GMT</pubDate>
      <guid>https://communities.sas.com/t5/Statistical-Procedures/Help-with-Restricted-Cubic-Splines-Code-Optimization-and/m-p/968163#M48653</guid>
      <dc:creator>SteveDenham</dc:creator>
      <dc:date>2025-06-04T16:37:50Z</dc:date>
    </item>
  </channel>
</rss>

