<?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: Picking up Every Second Last Observation in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/550499#M152851</link>
    <description>&lt;P&gt;&lt;EM&gt;&amp;gt;But I think you are essentially just doing this logic.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;Yes, and your code is more legible, again!&lt;/P&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/31461"&gt;@mkeintz&lt;/a&gt;&amp;nbsp;The speed is the same&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data TEMP1;
  do I=1 to 5e6;
    do T=1 to ceil(ranuni(1)*10);
      Y=rand("normal");
      output;
    end;
  end;
run;

%* POINT=      40 s;
data TEMP2(compress=no);
  set TEMP1;
  by I ;
  if first.I then START = _N_;
  retain START;
  if last.I then do POINT = max(START, _N_ - 2) to _N_;
    set TEMP1 point=POINT;
    output;
  end;
  drop START;
run;

%* DOW + BY      13 s;
data TEMP3(compress=no);
  do _N=1 by 1 until(last.I);
    set TEMP1;
    by I;
  end;
  do _N2=1 to _N;
    set TEMP1;
    if _N2 &amp;gt;= _N-2 then output;
  end;
  drop _N _N2;
run;

%* Read-ahead + BY     18 s ;
data TEMP4(compress=no);
  set TEMP1 nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if I ne I1 then KEEP=1;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;                        if keep;
run ;
            
%* Read-ahead    13s ;
data TEMP5(compress=no);
  set TEMP1;
  if LASTOBS then output;
  else set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  if (I ne I1) then output ;
run;
     &lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Fri, 12 Apr 2019 04:53:13 GMT</pubDate>
    <dc:creator>ChrisNZ</dc:creator>
    <dc:date>2019-04-12T04:53:13Z</dc:date>
    <item>
      <title>Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549139#M152339</link>
      <description>&lt;P&gt;Suppose there is a panel data set indexed by "i" and "t," respectively.&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp;
call streaminit(1);
do i=1 to 500;
do t=1 to 10;
y=rand("normal");
output;
end;
end;
run;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Assume that one picks up every first, second, and third observations for all "i" using FIRST and LAG.&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
set temp;
by i t;
if first.i or lag1(first.i) or lag2(first.i);
run;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Can one pick up every last, second last, and third last observations in a similar way? Though LAST is available for all the last observations, the second and third last observations are not easy.&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp2;
set temp;
by i t;
if last.i;
run;&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;Is PROC SORT plus DESCENDING the only option here?&lt;/P&gt;&lt;P&gt;P.S. Though LAG7 and LAG8 are possible for this case, please assume a general unbalanced panel data set.&lt;/P&gt;</description>
      <pubDate>Sun, 07 Apr 2019 23:45:33 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549139#M152339</guid>
      <dc:creator>Junyong</dc:creator>
      <dc:date>2019-04-07T23:45:33Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549144#M152340</link>
      <description>Make two passes through the data.  For example:&lt;BR /&gt;&lt;BR /&gt;data want;&lt;BR /&gt;tot_count=0;&lt;BR /&gt;do until (last.id) ;&lt;BR /&gt;  set have;&lt;BR /&gt;  by id;&lt;BR /&gt;  tot_count + 1;&lt;BR /&gt;end;&lt;BR /&gt;K=0;&lt;BR /&gt;do until (last.id) ;&lt;BR /&gt;  set have;&lt;BR /&gt;  by id;&lt;BR /&gt;  k + 1;&lt;BR /&gt;  if k in (1, 2, 3, tot_count, tot_count-1, tot_count-2) then output;&lt;BR /&gt;end;&lt;BR /&gt;drop k tot_count;&lt;BR /&gt;run;</description>
      <pubDate>Mon, 08 Apr 2019 02:07:48 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549144#M152340</guid>
      <dc:creator>Astounding</dc:creator>
      <dc:date>2019-04-08T02:07:48Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549151#M152342</link>
      <description>&lt;P&gt;Reading ahead works to:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data TEMP2;
  set TEMP nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Reading 3 observations ahead allows to mark the first 3 of the shifted observations. These match with the last 3 of the original observations .&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 03:15:31 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549151#M152342</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T03:15:31Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549152#M152343</link>
      <description>&lt;P&gt;Random access keeps I/O to a minimum:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;proc sort data=sashelp.class out=have; by sex name; run;

data last3;
set have; by sex;
if first.sex then start = _n_;
retain start;
if last.sex then do point = max(start, _n_ - 2) to _n_;
    set have point=point;
    output;
    end;
drop start;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;EDIT Added retain statement as suggested by&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt; . &lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:11:59 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549152#M152343</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2019-04-08T04:11:59Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549156#M152346</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/462"&gt;@PGStats&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;POINT= is extremely slow. It is best avoided unless the number of records retrieved is low.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 03:41:16 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549156#M152346</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T03:41:16Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549158#M152347</link>
      <description>&lt;P&gt;That's true in general &lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/16961"&gt;@ChrisNZ&lt;/a&gt;&amp;nbsp;, but here, the records accessed at random have just been read sequentially, and there are only three of them per by-group. So, random access should be at least considered.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 03:52:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549158#M152347</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2019-04-08T03:52:19Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549160#M152349</link>
      <description>&lt;P&gt;&lt;EM&gt;&amp;gt; the records accessed at random have just been read sequentially, and there are only three of them per by-group. So, random access should be at least considered.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/462"&gt;@PGStats&lt;/a&gt;&amp;nbsp;Fair enough.&lt;/P&gt;
&lt;P&gt;And if groups can have fewer than 3 observations, additional logic is required.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 03:59:59 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549160#M152349</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T03:59:59Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549163#M152351</link>
      <description>&lt;P&gt;Are I &amp;amp; T fixed at (say) 500 &amp;amp; 10, respectively?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If so, then just filter the top 3 values of T (8, 9, 10)?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
	set temp;
	where t in (8,9,10);
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Or if this is oversimplifying, then try (something like) this:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
	set temp;
	by i t;
	OnePrev=lag1(y); TwoPrev=lag2(y);
	if last.i then output;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:02:26 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549163#M152351</guid>
      <dc:creator>AndrewHowell</dc:creator>
      <dc:date>2019-04-08T04:02:26Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549164#M152352</link>
      <description>&lt;P&gt;Variable START in my code accounts for that possibility.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:02:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549164#M152352</guid>
      <dc:creator>PGStats</dc:creator>
      <dc:date>2019-04-08T04:02:37Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549166#M152353</link>
      <description>&lt;P&gt;POINT= seems to work great for this problem.&lt;/P&gt;
&lt;P&gt;But a double DOW seems to be a little faster.&lt;/P&gt;
&lt;P&gt;Using extra SET statements to look ahead seems to be slowest.&lt;/P&gt;
&lt;P&gt;For 5,000,000 observations:&lt;/P&gt;
&lt;PRE&gt;320   data temp2;
321     set temp1;
322     by I ;
323     if first.i then start = _n_;
324     retain start;
325     if last.i then do point = max(start, _n_ - 2) to _n_;
326       set temp1 point=point;
327       output;
328     end;
329     drop start;
330   run;

NOTE: There were 5000000 observations read from the data set WORK.TEMP1.
NOTE: The data set WORK.TEMP2 has 1500000 observations and 3 variables.
NOTE: DATA statement used (Total process time):
      real time           0.57 seconds
      cpu time            0.60 seconds


331
332   data TEMP3;
333   do _n=1 by 1 until(last.i);
334     set temp1;
335     by i;
336   end;
337   do _n2=1 to _n;
338     set temp1;
339     if _n2 &amp;gt;= _n-2 then output;
340   end;
341   drop _n _n2;
342   run;

NOTE: There were 5000000 observations read from the data set WORK.TEMP1.
NOTE: There were 5000000 observations read from the data set WORK.TEMP1.
NOTE: The data set WORK.TEMP3 has 1500000 observations and 3 variables.
NOTE: DATA statement used (Total process time):
      real time           0.48 seconds
      cpu time            0.48 seconds


343
344
345   data TEMP4;
346     set TEMP1 end=eof1 ;
347     by I;
348     if not eof1 then set temp1(firstobs=2 keep=I rename=(i=i2)) end=eof2;
349     by i2 ;
350     if not eof2 then set temp1(firstobs=3 keep=I rename=(i=i3)) end=eof3;
351     by i3 ;
352     if last.i or (last.i2 and i=i2) or (last.i3 and i=i3);
353   run;

NOTE: There were 5000000 observations read from the data set WORK.TEMP1.
NOTE: There were 4999999 observations read from the data set WORK.TEMP1.
NOTE: There were 4999998 observations read from the data set WORK.TEMP1.
NOTE: The data set WORK.TEMP4 has 1500000 observations and 5 variables.
NOTE: DATA statement used (Total process time):
      real time           1.20 seconds
      cpu time            1.17 seconds
&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:26:57 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549166#M152353</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2019-04-08T04:26:57Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549172#M152357</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp; For speed, my tests confirm your findings: DOW&amp;nbsp; &amp;gt; read-ahead &amp;gt; POINT=&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;Having only one BY statement is probably the reason. BY statements really hinder speed.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:32:52 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549172#M152357</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T04:32:52Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549174#M152359</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;A DOW with no BY seems ever so slightly faster&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
call streaminit(1);
do i=1 to 5e5;
do t=1 to 10;
y=rand("normal");
output;
end;
end;
run;

%* POINT=   ==&amp;gt; 6.99 real/6.3 CPU seconds;
data temp2;
  set temp1;
  by I ;
  if first.i then start = _n_;
  retain start;
  if last.i then do point = max(start, _n_ - 2) to _n_;
    set temp1 point=point;
    output;
  end;
  drop start;
run;

%* read ahead   ==&amp;gt; 4.74 real/3.82 CPU seconds;
data TEMP3;
  set TEMP1 nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;                        if keep;
run;

%* DOW + BY   ==&amp;gt; 3.12 real/2.62 CPU seconds;
data TEMP4;
do _n=1 by 1 until(last.i);
  set temp1;
  by i;
end;
do _n2=1 to _n;
  set temp1;
  if _n2 &amp;gt;= _n-2 then output;
end;
drop _n _n2;
run;

%* DOW no BY   ==&amp;gt; 3.09 real/2.45 CPU seconds;
data TEMP5;
do _n=1 by 1 until(_N &amp;gt;1 and I ne lag(I));
  set temp1;     
end;        
do _n2=1 to _n;
  set temp1 nobs=NOBS;
  if _N &amp;gt; _n2 &amp;gt;= _n-3 | _N2&amp;gt;=NOBS-3 then output;
end;
drop _n _n2;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 04:52:11 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549174#M152359</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T04:52:11Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549429#M152445</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;You use three SET BY, hence the poor speed, since BY adds so much overhead. They are not needed.&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 21:36:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549429#M152445</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T21:36:00Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549430#M152446</link>
      <description>How can you find the 3rd and 2nd to last without the BY statements?&lt;BR /&gt;</description>
      <pubDate>Mon, 08 Apr 2019 21:39:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549430#M152446</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2019-04-08T21:39:18Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549432#M152447</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;See my first post&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here is my benchmark:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
call streaminit(1);
do i=1 to 5e5;
do t=1 to 10;
y=rand("normal");
output;
end;
end;
run;

%* POINT=   ==&amp;gt; 6.99 real/6.3 CPU seconds;
data temp2;
  set temp1;
  by I ;
  if first.i then start = _n_;
  retain start;
  if last.i then do point = max(start, _n_ - 2) to _n_;
    set temp1 point=point;
    output;
  end;
  drop start;
run;

%* read ahead   ==&amp;gt; 4.74 real/3.82 CPU seconds;
data TEMP3;
  set TEMP1 nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;                        if keep;
run;

%* DOW + BY   ==&amp;gt; 3.12 real/2.62 CPU seconds;
data TEMP4;
do _n=1 by 1 until(last.i);
  set temp1;
  by i;
end;
do _n2=1 to _n;
  set temp1;
  if _n2 &amp;gt;= _n-2 then output;
end;
drop _n _n2;
run;

%* DOW no BY   ==&amp;gt; 3.09 real/2.45 CPU seconds;
data TEMP5;
do _n=1 by 1 until(_N &amp;gt;1 and I ne lag(I));
  set temp1;     
end;        
do _n2=1 to _n;
  set temp1 nobs=NOBS;
  if _N &amp;gt; _n2 &amp;gt;= _n-3 | _N2&amp;gt;=NOBS-3 then output;
end;
drop _n _n2;
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 08 Apr 2019 21:58:17 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549432#M152447</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-08T21:58:17Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549450#M152456</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/16961"&gt;@ChrisNZ&lt;/a&gt;&amp;nbsp; But it doesn't get the same output dataset.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp1;
call streaminit(1);
do i=1 to 5000;
do t=1 to ceil(i/10);
y=rand("normal");
output;
end;
end;
run;

data TEMP2;
do _n=1 by 1 until(last.i);
  set temp1;
  by i;
end;
do _n2=1 to _n;
  set temp1;
  if _n2 &amp;gt;= _n-2 then output;
end;
drop _n _n2;
run;

data TEMP3;
  set TEMP1 nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;                        
  if keep;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;PRE&gt;The COMPARE Procedure                                                                                      
Comparison of WORK.TEMP2 with WORK.TEMP3                                                                   
(Method=EXACT)                                                                                             
                                                                                                           
Observation Summary                                                                                        
                                                                                                           
Observation      Base  Compare  ID                                                                         
                                                                                                           
First Obs           1        .  i=1 t=1                                                                    
First Match         4        1  i=4 t=1                                                                    
Last  Obs       14970    14967  i=5000 t=500                                                               
                                                                                                           
Number of Observations in Common: 14967.                                                                   
Number of Observations in WORK.TEMP2 but not in WORK.TEMP3: 3.                                             
Total Number of Observations Read from WORK.TEMP2: 14970.                                                  
Total Number of Observations Read from WORK.TEMP3: 14967.                                                  
                                                                                                           
Number of Observations with Some Compared Variables Unequal: 0.                                            
Number of Observations with All Compared Variables Equal: 14967.                                           
                                                                                                           
NOTE: No unequal values were found. All values compared are exactly equal.  &lt;/PRE&gt;</description>
      <pubDate>Tue, 09 Apr 2019 00:02:09 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549450#M152456</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2019-04-09T00:02:09Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549468#M152470</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/159"&gt;@Tom&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If the assumptions about the data change, the code needs to adapt to the new conditions.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The hierarchy of the run times remains the same.&amp;nbsp; &amp;nbsp;POINT=&amp;nbsp; &amp;nbsp;&amp;gt;&amp;nbsp; &amp;nbsp;READ-AHEAD&amp;nbsp; &amp;nbsp;&amp;gt;&amp;nbsp; &amp;nbsp;DOW+BY&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data TEMP3;
  set TEMP1 nobs=NOBS;
  by I T; 
  if ^LASTOBS then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS;
  by I1 ;
  if I ne I1 then KEEP=1;
  if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
  if _N_ &amp;gt; NOBS-3  then KEEP=1;                        if keep;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Comparison of WORK.TEMP2 with WORK.TEMP3&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;NOTE: No unequal values were found. All values compared equal.&lt;/P&gt;</description>
      <pubDate>Tue, 09 Apr 2019 03:58:30 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549468#M152470</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-09T03:58:30Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549471#M152472</link>
      <description>&lt;P&gt;Note that an explicit DOW has a speed advantage over the implicit data step loop.&lt;/P&gt;
&lt;P&gt;The first step is faster than the second one just because we don't use the implicit loop logic.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data TEMP3a;
  do N=1 by 1 until (LASTOBS);
    set TEMP1 nobs=NOBS end=LASTOBS;
    if ^LASTOBS1 then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS1;
    by I1 ;       
    if I ne I1 then KEEP=1;
    if N &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
    if N &amp;gt; NOBS-3  then KEEP=1;                        
    if KEEP then output;           
    KEEP=0; 
  end;
run;
 
data TEMP3b;
    set TEMP1 nobs=NOBS ;
    if ^LASTOBS1 then set TEMP1(firstobs=4 keep=I rename=(I=I1)) end=LASTOBS1;
    by I1 ;                         
    if I ne I1 then KEEP=1;
    if _N_ &amp;gt; 3 then if first.I1 or lag1(first.I1) or lag2(first.I1) then KEEP=1;
    if _N_ &amp;gt; NOBS-3  then KEEP=1;                  
    if KEEP ;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Your DOW step is faster than mine though (and arguably more legible), so better for the question at hand.&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>Tue, 09 Apr 2019 04:03:00 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549471#M152472</guid>
      <dc:creator>ChrisNZ</dc:creator>
      <dc:date>2019-04-09T04:03:00Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549477#M152475</link>
      <description>&lt;P&gt;I'd be interested in knowing whether this simpler program is as fast:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
  if end_of_temp=0 then set temp (keep=i t) end=end_of_temp;
  by i t ;
  if _n_&amp;gt;=3 then set temp;
  if last.i or lag(last.i) or lag2(last.i);
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The "if end_of_temp=0" condition prevents the data step from prematurely stopping, so that the "if _n_&amp;gt;=3 then set ...." statement can read the entire data set.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This program will include by groups with less than 3 observations.&amp;nbsp; If you want to exclude such groups, then modify the subsetting if to&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;  if (last.i or lag(last.i) or lag2(last.i)) and lag2(i)=i;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 09 Apr 2019 05:02:06 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549477#M152475</guid>
      <dc:creator>mkeintz</dc:creator>
      <dc:date>2019-04-09T05:02:06Z</dc:date>
    </item>
    <item>
      <title>Re: Picking up Every Second Last Observation</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549479#M152476</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/16961"&gt;@ChrisNZ&lt;/a&gt;&amp;nbsp; I couldn't figure out the logic of why your step should work.&lt;/P&gt;
&lt;P&gt;But I think you are essentially just doing this logic.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp3;
  set temp1;
  if not eof then set temp1(in=in1 firstobs=4 keep=I rename=(I=I1)) end=eof;
  else in1=0;
  if (I ne I1) or not in1;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Or put another way.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data temp3;
  set temp1;
  if eof then output;
  else set temp1(firstobs=4 keep=I rename=(I=I1)) end=eof;
  if (I ne I1) then output ;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Tue, 09 Apr 2019 05:19:05 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Picking-up-Every-Second-Last-Observation/m-p/549479#M152476</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2019-04-09T05:19:05Z</dc:date>
    </item>
  </channel>
</rss>

