<?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: Calculate monthly ranges using macro in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566615#M159270</link>
    <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13879"&gt;@Reeza&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://communities.sas.com/t5/SAS-Programming/Rounding-the-fixed-number-to-produce-unoverlapped-interval-range/m-p/566602#M159263" target="_blank" rel="noopener"&gt;https://communities.sas.com/t5/SAS-Programming/Rounding-the-fixed-number-to-produce-unoverlapped-interval-range/m-p/566602#M159263&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I think PaigeMiller and I just fixed the problem under the new forum. Please let me know if any comments.&lt;/P&gt;</description>
    <pubDate>Mon, 17 Jun 2019 15:24:41 GMT</pubDate>
    <dc:creator>Cruise</dc:creator>
    <dc:date>2019-06-17T15:24:41Z</dc:date>
    <item>
      <title>Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566335#M159147</link>
      <description>&lt;P&gt;Hi Folks:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I'm trying to present 1-year survival by unit of month in the Table below. However, my attempt to modify a macro deisgnated to calculate annual to monthly rate is not successful and I have the column "range" produced with overlapped intervals. Desired output is shown in red. The second patient died before 12-months.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The macro %lexis is attached to this post and can be found here too: &lt;A href="http://www.pauldickman.com/survival/sas/lexis.sas" target="_blank" rel="noopener"&gt;http://www.pauldickman.com/survival/sas/lexis.sas&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Could you please help me produce the desired output?&lt;/P&gt;
&lt;P&gt;I greatly appreciate your time!&lt;/P&gt;
&lt;P&gt;Thanks in advance.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="desired outcome.png" style="width: 600px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/30294i89929F989C7DCB92/image-size/large?v=v2&amp;amp;px=999" role="button" title="desired outcome.png" alt="desired outcome.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data have;
input id age yydx year8594 dx exit d;
cards;
1 78 1978 0 6854 9365 1 
21 76 1976 0 6063 6078 1 
;
%include 'C:\lexis.sas';

%lexis (data=have, out=have, breaks = %str( 0 to 1 by 0.083333), origin = dx, entry = dx, exit = exit,
fail = d, scale = 30.4, right = right, risk = y, lrisk = ln_y, lint = length, cint = w, nint = fu);

data have; set have;
range=put(left,4.1) || ' - ' || left(put(right,4.1));
run;
proc print; run;&lt;/CODE&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;%LEXIS&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro Lexis ( data = ,       /* Data set with original data,             */
                              /*    defaults to _last_                    */
                out = ,       /* Where to put the result,                 */
                              /*    defaults to &amp;amp;data.                    */
              entry = entry,  /* Variable holding the entry date          */
               exit = exit,   /* Variable holding the exit date           */
               fail = fail,   /* Variable holding the exit status         */
                              /* If any of the entry, exit or fail        */
                              /*    variables are missing the person is   */
                              /*    discarded from the computations.      */
             breaks = ,       /* Specification of the cutpoints on        */
                              /*    the transformed scale.                */
                              /*    Syntax as for a do statement.         */
                              /*    The ONLY Mandatory argument.          */
               cens = 0,      /* Code for censoring (may be a variable)   */
              scale = 1,      /* Factor to transform from the scale       */
                              /*    of entry and exit to the scale        */
                              /*    where breaks and risk are given       */
             origin = 0,      /* Origin of the transformed scale          */
               risk = risk,   /* Variable recieving the risk time         */
              lrisk = lrisk,  /* Variable recieving the log(risk time)    */
               left = left,   /* Variable recieving left  endpoint of int */
              other = ,       /* Other dataset statements to be used such */
                              /*     as: %str( format var ddmmyy10. ; )   */
                              /*     or: %str( label risk ="P-years" ; )  */
               disc = discrd, /* Dataset holding discarded observations   */
           /*-------------------------------------------------------------*/
           /* Variables for making life-tables and other housekeeping:    */
           /* These will only appear in the output dataset if given here  */
           /* The existence of these arguments are tested in the macro so */
           /* they cannot have names that are also logical operators such */
           /* as: or, and, eq, ne, le, lt, gt.                            */
           /*-------------------------------------------------------------*/
              right = ,       /* Variable recieving right endpoint of int */
               lint = ,       /* Variable recieving interval length       */
            os_left = ,       /* Variable recieving left  endpoint of int */
           os_right = ,       /* Variable recieving right endpoint of int */
            os_lint = ,       /* Variable recieving interval length       */
                              /*    - the latter three on original scale  */
               cint = ,       /* Variable recieving censoring indicator   */
                              /*    for the current input record          */
               nint =         /* Variable recieving index of follow-up    */
                              /*       interval;                          */
              );

%if &amp;amp;breaks.= %then %put ERROR: breaks MUST be specified. ;
%if &amp;amp;data.  = %then %let data = &amp;amp;syslast. ;
%if &amp;amp;out.   = %then %do ;
                    %let out=&amp;amp;data. ;
                    %put
NOTE: Output dataset not specified, input dataset %upcase(&amp;amp;data.) will be overwritten. ;
                  %end ;

data &amp;amp;disc. &amp;amp;out. ;
  set &amp;amp;data. ;
  if ( nmiss ( &amp;amp;entry., &amp;amp;exit., &amp;amp;fail., &amp;amp;origin. ) gt 0 ) 
     then do ; output &amp;amp;disc. ;
               goto next ;
          end ;
  * Labelling of variables ;
  label &amp;amp;entry.  = 'Entry into interval' ;
  label &amp;amp;exit.   = 'Exit from interval' ;
  label &amp;amp;fail.   = 'Failure indicator for interval' ;
  label &amp;amp;risk.   = 'Risktime in interval' ;
  label &amp;amp;lrisk.  = 'Natural log of risktime in interval' ;
  label &amp;amp;left.   = 'Left endpoint of interval (transformed scale)' ;
%if    &amp;amp;right.^= %then  label &amp;amp;right. = 'Right endpoint of interval (transformed scale)' ; ;
%if     &amp;amp;lint.^= %then  label &amp;amp;lint. = 'Interval width (transformed scale)' ; ;
%if  &amp;amp;os_left.^= %then  label &amp;amp;os_left. = 'Left endpoint of interval (original scale)' ; ;
%if &amp;amp;os_right.^= %then  label &amp;amp;os_right. = 'Right endpoint of interval (original scale)' ; ; 
%if  &amp;amp;os_lint.^= %then  label &amp;amp;os_lint. = 'Interval width (original scale)' ; ;
%if     &amp;amp;cint.^= %then  label &amp;amp;cint. = 'Indicator for censoring during the interval' ; ;
%if     &amp;amp;nint.^= %then  label &amp;amp;nint. = 'Sequential index for follow-up interval' ; ;
  &amp;amp;other. ;
  drop _entry_ _exit_ _fail_
       _origin_ _break_
       _cur_r _cur_l _int_r _int_l
       _first_ _cint_ _nint_;

/*
Temporary variables in this macro:

  _entry_  holds entry date on the transformed timescale
  _exit_   holds exit  date on the transformed timescale
  _fail_   holds exit  status
  _break_  current cut-point
  _origin_ origin of the time scale
  _cur_l   left  endpoint of current risk interval
  _cur_r   right endpoint of current risk interval
  _int_l   left  endpoint of current break interval
  _int_r   right endpoint of current break interval
  _first_  indicator for processing of the first break interval
  _cint_   indicator for censoring during the interval
  _nint_   sequential index of interval
   
If a variable with any of these names appear in the input dataset it will
not be present in the output dataset.
*/

  _origin_ = &amp;amp;origin. ;
  _entry_  = ( &amp;amp;entry. - _origin_ ) / &amp;amp;scale. ;
  _exit_   = ( &amp;amp;exit.  - _origin_ ) / &amp;amp;scale. ;
  _fail_   = &amp;amp;fail. ;
  _cur_l   = _entry_ ;
  _first_  = 1 ;

  do _break_ = &amp;amp;breaks. ;
     if _first_ then do ;
        _nint_=-1;
        _cur_l = max ( _break_, _entry_ ) ;
        _int_l = _break_ ;
     end ;
     _nint_ + 1;
     _first_ = 0 ;
     _int_r = _break_ ;
     _cur_r = min ( _exit_, _break_ ) ;
     if _cur_r gt _cur_l then do ;
/*
Endpoints of risk interval are put back on original scale.
If any of left or right are specified the corresponding endpoint
of the break-interval are output.
*/
        &amp;amp;entry.  = _cur_l * &amp;amp;scale. + _origin_ ;
        &amp;amp;exit.   = _cur_r * &amp;amp;scale. + _origin_ ;
        &amp;amp;risk.   = _cur_r - _cur_l ;
        &amp;amp;lrisk.  = log ( &amp;amp;risk. ) ;
        &amp;amp;fail.   = _fail_ * ( _exit_ eq _cur_r ) +
                   &amp;amp;cens. * ( _exit_ gt _cur_r ) ;
        _cint_   = not( _fail_ ) * ( _exit_ eq _cur_r ) ;            
        %if     &amp;amp;left.^= %then &amp;amp;left.     = _int_l ; ;
        %if    &amp;amp;right.^= %then &amp;amp;right.    = _int_r ; ;
        %if     &amp;amp;lint.^= %then &amp;amp;lint.     = _int_r - _int_l ; ;
        %if  &amp;amp;os_left.^= %then &amp;amp;os_left.  = _int_l * &amp;amp;scale. + _origin_ ; ;
        %if &amp;amp;os_right.^= %then &amp;amp;os_right. = _int_r * &amp;amp;scale. + _origin_ ; ; 
        %if  &amp;amp;os_lint.^= %then &amp;amp;os_lint.  = ( _int_r - _int_l ) * &amp;amp;scale. ; ;
        %if     &amp;amp;cint.^= %then &amp;amp;cint.     = _cint_ ; ;
        %if     &amp;amp;nint.^= %then &amp;amp;nint.     = _nint_ ; ;
        output &amp;amp;out. ;
     end ;
     _cur_l = max ( _entry_, _break_ ) ;
     _int_l = _break_ ;
  end ;
  next: ;
run ;

%mend Lexis ;&lt;/CODE&gt;&lt;/PRE&gt;</description>
      <pubDate>Sat, 15 Jun 2019 12:33:20 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566335#M159147</guid>
      <dc:creator>Cruise</dc:creator>
      <dc:date>2019-06-15T12:33:20Z</dc:date>
    </item>
    <item>
      <title>Re: Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566340#M159148</link>
      <description>I feel like SCALE is supposed to take care of that, but I don't have data to test. You can't really test on two records. &lt;BR /&gt;&lt;BR /&gt;Anyways, the breaks aren't set correctly either for given intervals are they? That seems like it doesn't quite match the data, but I'm not sure I understand that part correctly. I'll see if I have time this weekend to take a further stab, but this isn't a simple or straightforward problem IMO.</description>
      <pubDate>Sat, 15 Jun 2019 00:08:42 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566340#M159148</guid>
      <dc:creator>Reeza</dc:creator>
      <dc:date>2019-06-15T00:08:42Z</dc:date>
    </item>
    <item>
      <title>Re: Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566342#M159149</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13879"&gt;@Reeza&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks Reeza.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Below is the original macro for an annual rate. They used 365.4 for annual and I used 30.4 for monthly rate and modifying steps in breaks by 1/12=0.083333 and expending 1-10 to 1-12. According to the author's STATA tutorial, 'breaks' specify the cutpoints for the lifetable intervals as an&amp;nbsp; ascending numlist commencing at zero. The cutpoints need not be integer nor equidistant but the units must be years, e.g., specify breaks(0(0.0833)5) for monthly intervals up to 5 years.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;It will be great to hear from you back.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;SAS totorial on the same approach:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.pauldickman.com/survival/sas/relative_survival_using_sas.pdf" target="_blank"&gt;http://www.pauldickman.com/survival/sas/relative_survival_using_sas.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Dickman's STATA tutorial on the same macro&lt;/P&gt;
&lt;P&gt;&lt;A href="https://pdfs.semanticscholar.org/71e1/9adf869a8587ee5d03e0af2e5a3bdebcc42a.pdf" target="_blank" rel="noopener"&gt;https://pdfs.semanticscholar.org/71e1/9adf869a8587ee5d03e0af2e5a3bdebcc42a.pdf&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%lexis (data=&amp;amp;individ.,out=&amp;amp;individ., breaks = %str( 0 to 10 by 1 ), origin = dx,entry = dx, exit = exit,
fail = d,scale = 365.4, right = right,risk = y,lrisk = ln_y, lint = length,cint = w,nint = fu);
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;As you pointed out, using complete data is important. That is, original %lexis above doesn't produce correct range on the two subject only data. Full data is colon.sas7bdat which can be found here: &lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.pauldickman.com/survival/?dir=sas" target="_blank"&gt;http://www.pauldickman.com/survival/sas/survival.sas .&amp;nbsp;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Full SAS code is here: &lt;A href="http://www.pauldickman.com/survival/sas/survival.sas" target="_blank"&gt;http://www.pauldickman.com/survival/sas/survival.sas&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks again. &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Sat, 15 Jun 2019 13:29:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566342#M159149</guid>
      <dc:creator>Cruise</dc:creator>
      <dc:date>2019-06-15T13:29:23Z</dc:date>
    </item>
    <item>
      <title>Re: Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566432#M159193</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13879"&gt;@Reeza&lt;/a&gt; the author wrote me back and basically said the same thing you mentioned. Scale and the length variables. Do I have to round 0.08333 to more decimal places? &lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="paul.png" style="width: 600px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/30299iAD1731F3E48C91D9/image-size/large?v=v2&amp;amp;px=999" role="button" title="paul.png" alt="paul.png" /&gt;&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Sun, 16 Jun 2019 14:48:06 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566432#M159193</guid>
      <dc:creator>Cruise</dc:creator>
      <dc:date>2019-06-16T14:48:06Z</dc:date>
    </item>
    <item>
      <title>Re: Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566613#M159269</link>
      <description>I think you're not understanding breaks correctly because otherwise the example they set doesn't make sense. I think when looking at 0 to 1 that's setting breaks that are too small somehow, since I think the overall units are in days and that breaks it into fractions of days. Not sure what you're referencing above, but when I check the klexi.sas code, it shows breaks as days, such as 2, 5, 50 etc with the length of 365. So I think your breaks parameter is problematic. &lt;BR /&gt;&lt;BR /&gt;FYI - to debug this, I would use the original sample data, change it until I got similar (not exactly the same results) by changing the units to months from years and then using it on my actual data.</description>
      <pubDate>Mon, 17 Jun 2019 15:20:23 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566613#M159269</guid>
      <dc:creator>Reeza</dc:creator>
      <dc:date>2019-06-17T15:20:23Z</dc:date>
    </item>
    <item>
      <title>Re: Calculate monthly ranges using macro</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566615#M159270</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13879"&gt;@Reeza&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://communities.sas.com/t5/SAS-Programming/Rounding-the-fixed-number-to-produce-unoverlapped-interval-range/m-p/566602#M159263" target="_blank" rel="noopener"&gt;https://communities.sas.com/t5/SAS-Programming/Rounding-the-fixed-number-to-produce-unoverlapped-interval-range/m-p/566602#M159263&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I think PaigeMiller and I just fixed the problem under the new forum. Please let me know if any comments.&lt;/P&gt;</description>
      <pubDate>Mon, 17 Jun 2019 15:24:41 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Calculate-monthly-ranges-using-macro/m-p/566615#M159270</guid>
      <dc:creator>Cruise</dc:creator>
      <dc:date>2019-06-17T15:24:41Z</dc:date>
    </item>
  </channel>
</rss>

