<?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: Collapsing data - RETAIN statement doesn't seem to retain in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20527#M3210</link>
    <description>The retain *does* retain the values. The set, however, loads a new observation every implicit data step iteration. As it does, it overwrites the retained values. &lt;BR /&gt;
&lt;BR /&gt;
You need a separate array that is retained. As it turns out, temporary arrays are automatically retained. Using one, you can do this easily like so:&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data one;&lt;BR /&gt;
      input id $ qn a1 b1 c1 a2 b2 c2 a3 b3 c3;&lt;BR /&gt;
   datalines;&lt;BR /&gt;
   001 1 1 2 3 . . . . . .&lt;BR /&gt;
   001 2 . . . 2 7 2 . . .&lt;BR /&gt;
   001 3 . . . . . . 2 4 6&lt;BR /&gt;
   002 1 1 1 1 . . . . . .&lt;BR /&gt;
   002 2 . . . 2 3 4 . . .&lt;BR /&gt;
   002 3 . . . . . . 2 3 2&lt;BR /&gt;
   ;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   data stack;&lt;BR /&gt;
     set one;&lt;BR /&gt;
     by id qn;&lt;BR /&gt;
     array old[1:3,1:3] a1--c3;&lt;BR /&gt;
     array new[1:3,1:3] _temporary_; /* automatically retained */&lt;BR /&gt;
&lt;BR /&gt;
     if first.id then do;&lt;BR /&gt;
       do i = 1 to 3; do j = 1 to 3; new[i,j] = .;  end; end; &lt;BR /&gt;
     end; &lt;BR /&gt;
&lt;BR /&gt;
     do j = 1 to 3;&lt;BR /&gt;
       new[qn,j] = old[qn,j];&lt;BR /&gt;
     end;&lt;BR /&gt;
&lt;BR /&gt;
     if last.id then do;&lt;BR /&gt;
       do i = 1 to 3; do j = 1 to 3; old[i,j] = new[i,j]; end; end;&lt;BR /&gt;
       output;&lt;BR /&gt;
       keep id a1--c3;&lt;BR /&gt;
     end;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title 'Stacked data set';&lt;BR /&gt;
   proc print data = stack noobs;&lt;BR /&gt;
     var id a1--c3;   &lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   Stacked data set&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
If you get more experienced, you will have to eventually learn how to use the ever-popular DoW loop (see &lt;BR /&gt;
&lt;A href="http://www.devenezia.com/papers/other-authors/sesug-2002/TheMagnificentDO.pdf"&gt;http://www.devenezia.com/papers/other-authors/sesug-2002/TheMagnificentDO.pdf&lt;/A&gt;) and do something like below. Notice how nicely the code matches the programming logic: initialization comes first, then processing of the observations within a given by-group, followed by the processing to be done when the by-group has ended. &lt;BR /&gt;
&lt;BR /&gt;
DoW also frees us from retaining and explicitly outputting. Can you see why?&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data stack2;&lt;BR /&gt;
     if 0 then set one; /* to prep pdv */&lt;BR /&gt;
     array old[1:3,1:3] a1--c3;&lt;BR /&gt;
     array new[1:3,1:3] t1-t9;&lt;BR /&gt;
&lt;BR /&gt;
     /* initialize new */&lt;BR /&gt;
     call missing(of t:);&lt;BR /&gt;
    &lt;BR /&gt;
     /* DoW */&lt;BR /&gt;
     do until (last.id);&lt;BR /&gt;
       set one;&lt;BR /&gt;
       by id qn;&lt;BR /&gt;
       do j = 1 to 3;&lt;BR /&gt;
          new[qn,j] = old[qn,j];&lt;BR /&gt;
       end; &lt;BR /&gt;
     end;&lt;BR /&gt;
&lt;BR /&gt;
     /* output */&lt;BR /&gt;
     do i = 1 to 3; do j = 1 to 3; old[i,j] = new[i,j]; end; end;&lt;BR /&gt;
     keep id a1--c3;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack2;&lt;BR /&gt;
   proc print data=stack2 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   stack2&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
Or, you can simply do update as below. But in this case you are assuming that your data are clean in that every id has one and only one observation with qn=1, and given qn=x, there are no non-missing values other than in ax, bx, cx.&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data stack3;&lt;BR /&gt;
     update one(where=(qn=1)) one(drop=qn);&lt;BR /&gt;
     by id;&lt;BR /&gt;
     if last.id then output;&lt;BR /&gt;
     drop qn;&lt;BR /&gt;
   run;&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack3;&lt;BR /&gt;
   proc print data=stack3 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   stack3&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
Under the same assumptions, you can calculate maximum of each variable, by id, using some procs like so:&lt;BR /&gt;
[pre]&lt;BR /&gt;
   proc means data=one;&lt;BR /&gt;
     var a1--c3;&lt;BR /&gt;
     by id;&lt;BR /&gt;
     output out=stack4(drop=_:) max=;&lt;BR /&gt;
   run;&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack4;&lt;BR /&gt;
   proc print data=stack4 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /*&lt;BR /&gt;
   stack4&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]</description>
    <pubDate>Thu, 21 Oct 2010 15:37:18 GMT</pubDate>
    <dc:creator>chang_y_chung_hotmail_com</dc:creator>
    <dc:date>2010-10-21T15:37:18Z</dc:date>
    <item>
      <title>Collapsing data - RETAIN statement doesn't seem to retain</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20525#M3208</link>
      <description>All,&lt;BR /&gt;
I have data set and program as below :&lt;BR /&gt;
data one;&lt;BR /&gt;
input id$ qn a1 b1 c1 a2 b2 c2 a3 b3 c3;&lt;BR /&gt;
datalines;&lt;BR /&gt;
001 1 1 2 3 . . . . . .&lt;BR /&gt;
001 2 . . . 2 7 2 . . .&lt;BR /&gt;
001 3 . . . . . . 2 4 6&lt;BR /&gt;
002 1 1 1 1 . . . . . .&lt;BR /&gt;
002 2 . . . 2 3 4 . . .&lt;BR /&gt;
002 3 . . . . . . 2 3 2&lt;BR /&gt;
;&lt;BR /&gt;
data stack;&lt;BR /&gt;
set one;&lt;BR /&gt;
retain a1--c3;  * Accumulate valid data from line to line in old data set ;&lt;BR /&gt;
array cp[9] a1--c3;&lt;BR /&gt;
obsno = _N_;&lt;BR /&gt;
if qn = 3 then do;  * If last ob for a particular section - output and reset ;&lt;BR /&gt;
  output;&lt;BR /&gt;
  do x = 1 to 9;&lt;BR /&gt;
    cp&lt;X&gt; =.;&lt;BR /&gt;
  end;&lt;BR /&gt;
 end;&lt;BR /&gt;
run;&lt;BR /&gt;
proc print data = stack;&lt;BR /&gt;
var a1--c3;&lt;BR /&gt;
title 'Stacked data set';&lt;BR /&gt;
run;&lt;BR /&gt;
I'm trying to get is this :&lt;BR /&gt;
001 1 2 3 2 7 2 2 4 6&lt;BR /&gt;
002 1 1 1 2 3 4 2 3 2&lt;BR /&gt;
What I get is this:&lt;BR /&gt;
001  . . . . . . 2 4 6&lt;BR /&gt;
002  . . . . . . 2 3 2&lt;BR /&gt;
Apparently, RETAIN is allowing valid values to be overwritten by missing values, which is what I'm trying to avoid.  I think it has to do with how the PDV reads in and handles the data.&lt;BR /&gt;
Does anybody have an alternate way to do this ?  I wish there were a SUPERRETAIN in SAS like the %SUPERQ macro function...&lt;BR /&gt;
Any help would be much appreciated.  I searched the archives for tips, but couldn't find anything I could use for this problem.&lt;BR /&gt;
Barry Walton&lt;BR /&gt;
Barry.Walton@millersville.edu&lt;/X&gt;</description>
      <pubDate>Thu, 21 Oct 2010 14:14:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20525#M3208</guid>
      <dc:creator>enginemane44</dc:creator>
      <dc:date>2010-10-21T14:14:37Z</dc:date>
    </item>
    <item>
      <title>Re: Collapsing data - RETAIN statement doesn't seem to retain</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20526#M3209</link>
      <description>Consider that the RETAIN statement is used to manage previously undeclared SAS variables (not occurring in an incoming "SET" file) -- no question, your SET statement will replace same-named SAS variables, when executed in your DATA step.  &lt;BR /&gt;
&lt;BR /&gt;
Given the desired result you conveyed, I suspect you will need to define parallel-named SAS variables or consider using PROC SUMMARY with OUTPUT statement and MAX(...).&lt;BR /&gt;
&lt;BR /&gt;
Also, rather than hardcoding array logic, I would recommend using the DIM(&lt;ARRAYNAME&gt;) function with any applicable ARRAY element-range or max-element SAS programming logic, as with a DO/END code paragraph.&lt;BR /&gt;
&lt;BR /&gt;
Scott Barry&lt;BR /&gt;
SBBWorks, Inc.

Message was edited by: sbb&lt;/ARRAYNAME&gt;</description>
      <pubDate>Thu, 21 Oct 2010 14:36:24 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20526#M3209</guid>
      <dc:creator>sbb</dc:creator>
      <dc:date>2010-10-21T14:36:24Z</dc:date>
    </item>
    <item>
      <title>Re: Collapsing data - RETAIN statement doesn't seem to retain</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20527#M3210</link>
      <description>The retain *does* retain the values. The set, however, loads a new observation every implicit data step iteration. As it does, it overwrites the retained values. &lt;BR /&gt;
&lt;BR /&gt;
You need a separate array that is retained. As it turns out, temporary arrays are automatically retained. Using one, you can do this easily like so:&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data one;&lt;BR /&gt;
      input id $ qn a1 b1 c1 a2 b2 c2 a3 b3 c3;&lt;BR /&gt;
   datalines;&lt;BR /&gt;
   001 1 1 2 3 . . . . . .&lt;BR /&gt;
   001 2 . . . 2 7 2 . . .&lt;BR /&gt;
   001 3 . . . . . . 2 4 6&lt;BR /&gt;
   002 1 1 1 1 . . . . . .&lt;BR /&gt;
   002 2 . . . 2 3 4 . . .&lt;BR /&gt;
   002 3 . . . . . . 2 3 2&lt;BR /&gt;
   ;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   data stack;&lt;BR /&gt;
     set one;&lt;BR /&gt;
     by id qn;&lt;BR /&gt;
     array old[1:3,1:3] a1--c3;&lt;BR /&gt;
     array new[1:3,1:3] _temporary_; /* automatically retained */&lt;BR /&gt;
&lt;BR /&gt;
     if first.id then do;&lt;BR /&gt;
       do i = 1 to 3; do j = 1 to 3; new[i,j] = .;  end; end; &lt;BR /&gt;
     end; &lt;BR /&gt;
&lt;BR /&gt;
     do j = 1 to 3;&lt;BR /&gt;
       new[qn,j] = old[qn,j];&lt;BR /&gt;
     end;&lt;BR /&gt;
&lt;BR /&gt;
     if last.id then do;&lt;BR /&gt;
       do i = 1 to 3; do j = 1 to 3; old[i,j] = new[i,j]; end; end;&lt;BR /&gt;
       output;&lt;BR /&gt;
       keep id a1--c3;&lt;BR /&gt;
     end;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title 'Stacked data set';&lt;BR /&gt;
   proc print data = stack noobs;&lt;BR /&gt;
     var id a1--c3;   &lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   Stacked data set&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
If you get more experienced, you will have to eventually learn how to use the ever-popular DoW loop (see &lt;BR /&gt;
&lt;A href="http://www.devenezia.com/papers/other-authors/sesug-2002/TheMagnificentDO.pdf"&gt;http://www.devenezia.com/papers/other-authors/sesug-2002/TheMagnificentDO.pdf&lt;/A&gt;) and do something like below. Notice how nicely the code matches the programming logic: initialization comes first, then processing of the observations within a given by-group, followed by the processing to be done when the by-group has ended. &lt;BR /&gt;
&lt;BR /&gt;
DoW also frees us from retaining and explicitly outputting. Can you see why?&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data stack2;&lt;BR /&gt;
     if 0 then set one; /* to prep pdv */&lt;BR /&gt;
     array old[1:3,1:3] a1--c3;&lt;BR /&gt;
     array new[1:3,1:3] t1-t9;&lt;BR /&gt;
&lt;BR /&gt;
     /* initialize new */&lt;BR /&gt;
     call missing(of t:);&lt;BR /&gt;
    &lt;BR /&gt;
     /* DoW */&lt;BR /&gt;
     do until (last.id);&lt;BR /&gt;
       set one;&lt;BR /&gt;
       by id qn;&lt;BR /&gt;
       do j = 1 to 3;&lt;BR /&gt;
          new[qn,j] = old[qn,j];&lt;BR /&gt;
       end; &lt;BR /&gt;
     end;&lt;BR /&gt;
&lt;BR /&gt;
     /* output */&lt;BR /&gt;
     do i = 1 to 3; do j = 1 to 3; old[i,j] = new[i,j]; end; end;&lt;BR /&gt;
     keep id a1--c3;&lt;BR /&gt;
   run;&lt;BR /&gt;
&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack2;&lt;BR /&gt;
   proc print data=stack2 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   stack2&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
Or, you can simply do update as below. But in this case you are assuming that your data are clean in that every id has one and only one observation with qn=1, and given qn=x, there are no non-missing values other than in ax, bx, cx.&lt;BR /&gt;
[pre]&lt;BR /&gt;
   data stack3;&lt;BR /&gt;
     update one(where=(qn=1)) one(drop=qn);&lt;BR /&gt;
     by id;&lt;BR /&gt;
     if last.id then output;&lt;BR /&gt;
     drop qn;&lt;BR /&gt;
   run;&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack3;&lt;BR /&gt;
   proc print data=stack3 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /* on lst&lt;BR /&gt;
   stack3&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]&lt;BR /&gt;
&lt;BR /&gt;
Under the same assumptions, you can calculate maximum of each variable, by id, using some procs like so:&lt;BR /&gt;
[pre]&lt;BR /&gt;
   proc means data=one;&lt;BR /&gt;
     var a1--c3;&lt;BR /&gt;
     by id;&lt;BR /&gt;
     output out=stack4(drop=_:) max=;&lt;BR /&gt;
   run;&lt;BR /&gt;
   /* check */&lt;BR /&gt;
   title stack4;&lt;BR /&gt;
   proc print data=stack4 noobs;&lt;BR /&gt;
   run;&lt;BR /&gt;
   title;&lt;BR /&gt;
   /*&lt;BR /&gt;
   stack4&lt;BR /&gt;
   id     a1    b1    c1    a2    b2    c2    a3    b3    c3&lt;BR /&gt;
   001     1     2     3     2     7     2     2     4     6&lt;BR /&gt;
   002     1     1     1     2     3     4     2     3     2&lt;BR /&gt;
   */&lt;BR /&gt;
[/pre]</description>
      <pubDate>Thu, 21 Oct 2010 15:37:18 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20527#M3210</guid>
      <dc:creator>chang_y_chung_hotmail_com</dc:creator>
      <dc:date>2010-10-21T15:37:18Z</dc:date>
    </item>
    <item>
      <title>Re: Collapsing data - RETAIN statement doesn't seem to retain</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20528#M3211</link>
      <description>A SQL approach:&lt;BR /&gt;
&lt;BR /&gt;
proc sql;&lt;BR /&gt;
/*  create table want as*/&lt;BR /&gt;
  select&lt;BR /&gt;
    id&lt;BR /&gt;
    ,sum(a1) as a1&lt;BR /&gt;
    ,sum(b1) as b1&lt;BR /&gt;
    ,sum(c1) as c1&lt;BR /&gt;
    ,sum(a2) as a2&lt;BR /&gt;
    ,sum(b2) as b2&lt;BR /&gt;
    ,sum(c2) as c2&lt;BR /&gt;
    ,sum(a3) as a3&lt;BR /&gt;
    ,sum(b3) as b3&lt;BR /&gt;
    ,sum(c3) as c3&lt;BR /&gt;
  from one&lt;BR /&gt;
  group by id&lt;BR /&gt;
  order by id&lt;BR /&gt;
  ;&lt;BR /&gt;
quit;</description>
      <pubDate>Fri, 22 Oct 2010 09:22:12 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20528#M3211</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2010-10-22T09:22:12Z</dc:date>
    </item>
    <item>
      <title>Re: Collapsing data - RETAIN statement doesn't seem to retain</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20529#M3212</link>
      <description>Hello all,&lt;BR /&gt;
Chang_y_chung's program with the two-dimensional arrays worked.  A big thank you to him and the others who responded.  I'm not familiar with PROC SQL (hope to remedy that soon...), so I didn't try that approach - yet.  I'll have to review 2-D arrays - I use 1-D arrays extensively, but not the 2-D versions.&lt;BR /&gt;
Again, thanks to all who responded.&lt;BR /&gt;
Barry Walton</description>
      <pubDate>Fri, 22 Oct 2010 18:34:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Collapsing-data-RETAIN-statement-doesn-t-seem-to-retain/m-p/20529#M3212</guid>
      <dc:creator>enginemane44</dc:creator>
      <dc:date>2010-10-22T18:34:39Z</dc:date>
    </item>
  </channel>
</rss>

