looping in a macro

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

looping in a macro

mpirritano

Listerees,

 

I’m brand new to macros. I’m trying to translate some sas into spss.

 

I have 21 vectors. Let’s say I have a vector named vars1 composed of var1 var2 var3.  I want to say if var1 = 1, then make var2 and var3 = 0.

 

The vectors are of varying lengths.

 

So my macro so far looks like this.  Two main questions:

  1. Can I tell it to dynamically adjust the length of the loop depending upon the length of the vector? SAS has the ‘dim’ function to do this.
  2. And does my loop make sense? Can I use the !DO !DOEND ‘I’ to loop through my vectors which all have the name vars1 to vars21 as I’d use a subscript in a regular non-macro loop?

 

DEFINE !varnum().

!DO !I = 1 !TO 21.

 

loop #I = 1 to THIS NUMBER VARIES DEPENDING ON VECTOR.

      loop if (vars!I(#I)=1).

          compute vars!I(#I+1) = 0.

      end loop if (#I = 6).

end loop.

exe.

 

!DOEND.

 

!ENDDEFINE.

 

Any help is as always mucho appreciated!

 

Thanks

Matt

 

Matthew Pirritano, Ph.D.

Research Analyst IV

Medical Services Initiative (MSI)

Orange County Health Care Agency

(714) 568-5648

 

Reply | Threaded
Open this post in threaded view
|

Re: looping in a macro

Ruben Geert van den Berg
Dear Matthew,

I'm pretty new to macros as well but as far as my knowledge goes, there's two types of macro loops: index and list processing loops. For an index loop, the number of loops depends on the !to statement. The numbers surrounding this !to statement can be macro arguments in order to increase flexibility.

For a list processing loop, the number of elements in the list determines the number of loops. As far as I know, the macro will be unaware that a variable list containing [bli bla blo] has length = 3 but I think you could assign this 3 to an argument within the macro by a somewhat complicated construction. But I think that's not what you need.

I enclosed two examples of macro loops, I hope you find them useful, if not, let us know, OK?

Best of luck!

Ruben van den Berg

Methodologist

TNS NIPO

E: [hidden email]

P: +31 20 522 5738

I: www.tns-nipo.com


data list free/id.
begin data
1 2 3 4 5
end data.

*Index loop.

define !example_1 (start=!tokens (1) /end=!tokens (1))
!do !i =!start !to !end
comp !con("var",!i)=!i.
!doend
!enddefine.

!example_1 start=1 end=21.

exe.

*List processing loop.

define !example_2 (vars !cmdend )
!do !x !in (!vars)
comp !x=!x * 10.
!doend
!enddefine.

!example_2 vars=var1 var2 var3 var4 var5 var6 var7 var8 var9 var10 var11 var12 var13 var14 var15 var16 var17 var18 var19 var20 var21 .

exe.



Date: Thu, 1 Apr 2010 11:28:17 -0700
From: [hidden email]
Subject: looping in a macro
To: [hidden email]

Listerees,

 

I’m brand new to macros. I’m trying to translate some sas into spss.

 

I have 21 vectors. Let’s say I have a vector named vars1 composed of var1 var2 var3.  I want to say if var1 = 1, then make var2 and var3 = 0.

 

The vectors are of varying lengths.

 

So my macro so far looks like this.  Two main questions:

  1. Can I tell it to dynamically adjust the length of the loop depending upon the length of the vector? SAS has the ‘dim’ function to do this.
  2. And does my loop make sense? Can I use the !DO !DOEND ‘I’ to loop through my vectors which all have the name vars1 to vars21 as I’d use a subscript in a regular non-macro loop?

 

DEFINE !varnum().

!DO !I = 1 !TO 21.

 

loop #I = 1 to THIS NUMBER VARIES DEPENDING ON VECTOR.

      loop if (vars!I(#I)=1).

          compute vars!I(#I+1) = 0.

      end loop if (#I = 6).

end loop.

exe.

 

!DOEND.

 

!ENDDEFINE.

 

Any help is as always mucho appreciated!

 

Thanks

Matt

 

Matthew Pirritano, Ph.D.

Research Analyst IV

Medical Services Initiative (MSI)

Orange County Health Care Agency

(714) 568-5648

 



New Windows 7: Simplify what you do everyday. Find the right PC for you.
Reply | Threaded
Open this post in threaded view
|

Re: looping in a macro

Richard Ristow
In reply to this post by mpirritano
At 02:28 PM 4/1/2010, Pirritano, Matthew wrote:

I’m brand new to macros. I’m trying to translate some sas into spss.
 
I have 21 vectors. Let’s say I have a vector named vars1 composed of var1 var2 var3.  I want to say if var1 = 1, then make var2 and var3 = 0.  The vectors are of varying lengths.
 
Two main questions :
  • Can I tell [a macro] to dynamically adjust the length of the loop depending upon the length of the vector? SAS has the ‘dim’ function to do this.
Nope. (Sigh.) That's one of a number of useful SAS features that SPSS chose not to include, when otherwise bringing the transformation language up closer to the capabilities of SAS's DATA step. I don't know if you can even do this going into Python; I don't know whether Python has cognizance of the vectors in the dataset it's looking at. :-(

  • And does my loop make sense? Can I use the !DO !DOEND ‘I’ to loop through my vectors which all have the name vars1 to vars21 as I’d use a subscript in a regular non-macro loop?
Rather than debugging the macro, I'd change the approach. 'Idiomatic' SPSS uses macros far less than most SAS programmers do. Partly, that's because SAS's macro facility is, well, better; and partly, it's because SPSS has features that can often sidestep the need for a macro. One of those is DO REPEAT, a macro-like facility for stepping through parallel lists. Like the following, assuming that your requirement is that, if the first element of the vector is 1, all other elements should be made 0. (Note use of "#Ix" as the loop index variable. That's an SPSS 'scratch variable'; among other things, it isn't included in the output dataset.)

[TestData]
RecNum V1 V2 V3 W1 W2 W3 W4 X1 X2 X3 X4 X5

  001  13 12 14 14 12 11 14 15 13 13 14 13
  002  14 12 12  1 13 13 14 12 14 12 15 11
  003  12 13 15 13 13 12 12 11 12 13 14 13
  004  12 13 13  1 11 14 15 13 15 14 13 14
  005   1 13 13 12 14 13 12  1 13 12 13 14
  006  13 13 12  1 13 14 13 15 15 14 13 12
  007  13 14 13  1 14 12 14 14 14 11 13 15
  008   1 14 15 14 13 13 13 13 15 13 14 12

Number of cases read:  8    Number of cases listed:  8

 
VECTOR Vect3 = V1 TO V3
      /Vect4 = W1 TO W4
      /Vect5 = X1 TO X5.

DO REPEAT Vectr = Vect3 Vect4 Vect5
         /Limit =   3     4     5.
*  If the first element of a vector is 1, make all other elements 0  .
.  DO IF Vectr(1) EQ 1.
.     LOOP #Ix = 2 TO Limit.
.        COMPUTE Vectr(#Ix) = 0.
.     END LOOP.
.  END IF.
END REPEAT.

LIST.
 
List
|-----------------------------|---------------------------|
|Output Created               |03-APR-2010 16:58:31       |
|-----------------------------|---------------------------|
[TestData]
 
RecNum V1 V2 V3 W1 W2 W3 W4 X1 X2 X3 X4 X5

  001  13 12 14 14 12 11 14 15 13 13 14 13
  002  14 12 12  1  0  0  0 12 14 12 15 11
  003  12 13 15 13 13 12 12 11 12 13 14 13
  004  12 13 13  1  0  0  0 13 15 14 13 14
  005   1  0  0 12 14 13 12  1  0  0  0  0
  006  13 13 12  1  0  0  0 15 15 14 13 12
  007  13 14 13  1  0  0  0 14 14 11 13 15
  008   1  0  0 14 13 13 13 13 15 13 14 12

Number of cases read:  8    Number of cases listed:  8
=============================
APPENDIX: Test data, and code
=============================
*  C:\Documents and Settings\Richard\My Documents                    .
*    \Technical\spssx-l\Z 2010ab\                                    .
*    2010-04-01 Pirritano - looping in a macro.SPS                   .

*  In response to posting                                            .
*  Date:    Thu, 1 Apr 2010 11:28:17 -0700                           .
*  From:    "Pirritano, Matthew" <[hidden email]>              .
*  Subject: looping in a macro                                       .
*  To:      [hidden email]                                 .

*  "I have 21 vectors. Let’s say I have a vector named vars1         .
*  composed of var1 var2 var3.  I want to say if var1 = 1, then      .
*  make var2 and var3 = 0."                                          .

*  ................................................................. .
*  .................   Test data               ..................... .
SET RNG = MT       /* 'Mersenne twister' random number generator  */ .
SET MTINDEX = 2295 /*  Boston, MA telephone book                  */ .

INPUT PROGRAM.
.  NUMERIC RecNum (N3).
.  NUMERIC V1 TO V3
           W1 TO W4
           X1 TO X5  (F2).
.  VECTOR  AllData=V1 TO X5.
.  LOOP    RecNum = 1 TO 8.
.     LOOP #Ix = 1 TO 3+4+5.
.       COMPUTE AllData(#Ix) = 10+RV.BINOM(5,3/5).
.     END LOOP.
*     Special case: all vector-beginnings are 1                     .
*     with probability (a little more than) 1/3.                    .
.     DO REPEAT VectBegn = V1 W1 X1.
.        IF RV.BERNOULLI(1/3) VectBegn = 1.
.     END REPEAT.
.     END CASE.
.  END LOOP.
END FILE.
END INPUT PROGRAM.

DATASET NAME TestData.

*  .................   Test data               ..................... .

LIST.

VECTOR Vect3 = V1 TO V3
      /Vect4 = W1 TO W4
      /Vect5 = X1 TO X5.
     
DO REPEAT Vectr = Vect3 Vect4 Vect5
         /Limit =   3     4     5.
*  If the first element of a vector is 1, make all other elements 0  .
.  DO IF Vectr(1) EQ 1.
.     LOOP #Ix = 2 TO Limit.
.        COMPUTE Vectr(#Ix) = 0. 
.     END LOOP.
.  END IF.
END REPEAT.

LIST.

===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD
Reply | Threaded
Open this post in threaded view
|

Re: looping in a macro

mpirritano

Richard,

 

I wound up tweaking your syntax a little because I needed to set any ‘subsequent’ ones to zero. The first value in a vector was not always one, it could have been anywhere in the vector. Just wanted all subsequent values set to zero.  So here’s what I got:

 

do repeat vectr = vars1 to vars21

                   /limit  = 6  5  6  6  3  5  4  2  2  4  2  5  6  5  2  6  3  6  6  5  5.         

                   loop #I = 1 to limit.

                        do if (vectr(#I) = 1).

                             loop #J = (#I +1) to limit.

                                   compute vectr(#J) = 0.

                             end loop.

                         end if.

                    end loop.

end repeat.

exe.

 

Works great!

 

Thanks

Matt

 

Matthew Pirritano, Ph.D.

Research Analyst IV

Medical Services Initiative (MSI)

Orange County Health Care Agency

(714) 568-5648


From: Richard Ristow [mailto:[hidden email]]
Sent: Saturday, April 03, 2010 2:02 PM
To: Pirritano, Matthew; [hidden email]
Subject: Re: looping in a macro

 

At 02:28 PM 4/1/2010, Pirritano, Matthew wrote:


I’m brand new to macros. I’m trying to translate some sas into spss.
 
I have 21 vectors. Let’s say I have a vector named vars1 composed of var1 var2 var3.  I want to say if var1 = 1, then make var2 and var3 = 0.  The vectors are of varying lengths.
 
Two main questions :

  • Can I tell [a macro] to dynamically adjust the length of the loop depending upon the length of the vector? SAS has the ‘dim’ function to do this.

Nope. (Sigh.) That's one of a number of useful SAS features that SPSS chose not to include, when otherwise bringing the transformation language up closer to the capabilities of SAS's DATA step. I don't know if you can even do this going into Python; I don't know whether Python has cognizance of the vectors in the dataset it's looking at. :-(


  • And does my loop make sense? Can I use the !DO !DOEND ‘I’ to loop through my vectors which all have the name vars1 to vars21 as I’d use a subscript in a regular non-macro loop?

Rather than debugging the macro, I'd change the approach. 'Idiomatic' SPSS uses macros far less than most SAS programmers do. Partly, that's because SAS's macro facility is, well, better; and partly, it's because SPSS has features that can often sidestep the need for a macro. One of those is DO REPEAT, a macro-like facility for stepping through parallel lists. Like the following, assuming that your requirement is that, if the first element of the vector is 1, all other elements should be made 0. (Note use of "#Ix" as the loop index variable. That's an SPSS 'scratch variable'; among other things, it isn't included in the output dataset.)

[TestData]
RecNum V1 V2 V3 W1 W2 W3 W4 X1 X2 X3 X4 X5

  001  13 12 14 14 12 11 14 15 13 13 14 13
  002  14 12 12  1 13 13 14 12 14 12 15 11
  003  12 13 15 13 13 12 12 11 12 13 14 13
  004  12 13 13  1 11 14 15 13 15 14 13 14
  005   1 13 13 12 14 13 12  1 13 12 13 14
  006  13 13 12  1 13 14 13 15 15 14 13 12
  007  13 14 13  1 14 12 14 14 14 11 13 15
  008   1 14 15 14 13 13 13 13 15 13 14 12

Number of cases read:  8    Number of cases listed:  8

 
VECTOR Vect3 = V1 TO V3
      /Vect4 = W1 TO W4
      /Vect5 = X1 TO X5.

DO REPEAT Vectr = Vect3 Vect4 Vect5
         /Limit =   3     4     5.
*  If the first element of a vector is 1, make all other elements 0  .
.  DO IF Vectr(1) EQ 1.
.     LOOP #Ix = 2 TO Limit.
.        COMPUTE Vectr(#Ix) = 0.
.     END LOOP.
.  END IF.
END REPEAT.

LIST.
 
List
|-----------------------------|---------------------------|
|Output Created               |03-APR-2010 16:58:31       |
|-----------------------------|---------------------------|
[TestData]
 
RecNum V1 V2 V3 W1 W2 W3 W4 X1 X2 X3 X4 X5

  001  13 12 14 14 12 11 14 15 13 13 14 13
  002  14 12 12  1  0  0  0 12 14 12 15 11
  003  12 13 15 13 13 12 12 11 12 13 14 13
  004  12 13 13  1  0  0  0 13 15 14 13 14
  005   1  0  0 12 14 13 12  1  0  0  0  0
  006  13 13 12  1  0  0  0 15 15 14 13 12
  007  13 14 13  1  0  0  0 14 14 11 13 15
  008   1  0  0 14 13 13 13 13 15 13 14 12

Number of cases read:  8    Number of cases listed:  8
=============================
APPENDIX: Test data, and code
=============================
*  C:\Documents and Settings\Richard\My Documents                    .
*    \Technical\spssx-l\Z 2010ab\                                    .
*    2010-04-01 Pirritano - looping in a macro.SPS                   .

*  In response to posting                                            .
*  Date:    Thu, 1 Apr 2010 11:28:17 -0700                           .
*  From:    "Pirritano, Matthew" <[hidden email]>              .
*  Subject: looping in a macro                                       .
*  To:      [hidden email]                                 .

*  "I have 21 vectors. Let’s say I have a vector named vars1         .
*  composed of var1 var2 var3.  I want to say if var1 = 1, then      .
*  make var2 and var3 = 0."                                          .

*  ................................................................. .
*  .................   Test data               ..................... .
SET RNG = MT       /* 'Mersenne twister' random number generator  */ .
SET MTINDEX = 2295 /*  Boston, MA telephone book                  */ .

INPUT PROGRAM.
.  NUMERIC RecNum (N3).
.  NUMERIC V1 TO V3
           W1 TO W4
           X1 TO X5  (F2).
.  VECTOR  AllData=V1 TO X5.
.  LOOP    RecNum = 1 TO 8.
.     LOOP #Ix = 1 TO 3+4+5.
.       COMPUTE AllData(#Ix) = 10+RV.BINOM(5,3/5).
.     END LOOP.
*     Special case: all vector-beginnings are 1                     .
*     with probability (a little more than) 1/3.                    .
.     DO REPEAT VectBegn = V1 W1 X1.
.        IF RV.BERNOULLI(1/3) VectBegn = 1.
.     END REPEAT.
.     END CASE.
.  END LOOP.
END FILE.
END INPUT PROGRAM.

DATASET NAME TestData.

*  .................   Test data               ..................... .

LIST.

VECTOR Vect3 = V1 TO V3
      /Vect4 = W1 TO W4
      /Vect5 = X1 TO X5.
     
DO REPEAT Vectr = Vect3 Vect4 Vect5
         /Limit =   3     4     5.
*  If the first element of a vector is 1, make all other elements 0  .
.  DO IF Vectr(1) EQ 1.
.     LOOP #Ix = 2 TO Limit.
.        COMPUTE Vectr(#Ix) = 0. 
.     END LOOP.
.  END IF.
END REPEAT.

LIST.


Reply | Threaded
Open this post in threaded view
|

Re: looping in a macro

Jon K Peck
In reply to this post by Richard Ristow

Comments below.
Jon Peck
SPSS, an IBM Company
[hidden email]
312-651-3435



From: Richard Ristow <[hidden email]>
To: [hidden email]
Date: 04/03/2010 03:08 PM
Subject: Re: [SPSSX-L] looping in a macro
Sent by: "SPSSX(r) Discussion" <[hidden email]>





At 02:28 PM 4/1/2010, Pirritano, Matthew wrote:

I’m brand new to macros. I’m trying to translate some sas into spss.

I have 21 vectors. Let’s say I have a vector named vars1 composed of var1 var2 var3.  I want to say if var1 = 1, then make var2 and var3 = 0.  The vectors are of varying lengths.


Two main questions :
  • Can I tell [a macro] to dynamically adjust the length of the loop depending upon the length of the vector? SAS has the ‘dim’ function to do this.
Nope. (Sigh.) That's one of a number of useful SAS features that SPSS chose not to include, when otherwise bringing the transformation language up closer to the capabilities of SAS's DATA step. I don't know if you can even do this going into Python; I don't know whether Python has cognizance of the vectors in the dataset it's looking at. :-(
  • And does my loop make sense? Can I use the !DO !DOEND ‘I’ to loop through my vectors which all have the name vars1 to vars21 as I’d use a subscript in a regular non-macro loop?
Rather than debugging the macro, I'd change the approach. 'Idiomatic' SPSS uses macros far less than most SAS programmers do. Partly, that's because SAS's macro facility is, well, better; and partly, it's because SPSS has features that can often sidestep the need for a macro. One of those is DO REPEAT, a macro-like facility for stepping through parallel lists. Like the following, assuming that your requirement is that, if the first element of the vector is 1, all other elements should be made 0. (Note use of "#Ix" as the loop index variable. That's an SPSS 'scratch variable'; among other things, it isn't included in the output dataset.)

>>>Vectors in SPSS are transient and not visible to Python code, but it is very easy to define them on the Python side and then use that structure.  For example, if you want a set of variables consisting of all variables named var1 ... varn, you can get a VariableDict object in Python like this.

import spss, spssaux
myvector = spssaux.VariableDict(pattern="var\d+$")
Then you can iterate over the variables in this mini-dictionary or just get a list of these variables as
myvector.variables.

Use the spss.Dataset class to change these values.

This has the extra advantage that the variables do not have to be consecutive in the SPSS variable dictionary.

Regards,
Jon
Reply | Threaded
Open this post in threaded view
|

Re: looping in a macro

Richard Ristow
In reply to this post by mpirritano
At 01:37 PM 4/5/2010, Pirritano, Matthew wrote:

I wound up tweaking your syntax a little because I needed to set any ‘subsequent’ ones to zero. The first value in a vector was not always one, it could have been anywhere in the vector. Just wanted all subsequent values set to zero.  [Below is] what I got. Works great!

Great! I'm going to suggest one addition: a BREAK statement, to terminate the outer loop as soon as a 1 is reached and the remaining elements are set to 0. That'll speed things up a little bit. (Change not tested)

do repeat vectr = vars1 to vars21
                   /limit  = 6  5  6  6  3  5  4
                             2  2  4  2  5  6  5 
                             2  6  3  6  6  5  5.         
                   loop #I = 1 to limit.
                        do if (vectr(#I) = 1).
                             loop #J = (#I +1) to limit.
                                   compute vectr(#J) = 0.
                             end loop.
                             BREAK.

                         end if.
                    end loop.
end repeat.

(I've also deleted the ".exe", but I always do that, right?)

-Cheers, congratulations, and good luck,
 Richard
===================== To manage your subscription to SPSSX-L, send a message to [hidden email] (not to SPSSX-L), with no body text except the command. To leave the list, send the command SIGNOFF SPSSX-L For a list of commands to manage subscriptions, send the command INFO REFCARD