Administrator
|
/* Background: One of the more frustrating things about SPSS Macro
/* is its inability to resolve simple variable lists of the form VarX TO VarZ. /* For example one might want to iterate over a list of variables and do the following: FREQUENCIES Var. GRAPH/BAR(SIMPLE)=COUNT BY var. say: DEFINE !MyMacro (Varlist !CMDEND) !DO !VAR !IN (!Varlist) FREQUENCIES !VAR. GRAPH/BAR(SIMPLE)=COUNT BY !VAR. !DOEND !ENDDEFINE. !MyMacro Varlist=a b c d e. /* If one attempts to invoke this using a standard TO convention in the Varlist argument one gets !MyMacro Varlist=a TO e. FREQUENCIES a. GRAPH/BAR(SIMPLE)=COUNT BY a. FREQUENCIES TO. GRAPH/BAR(SIMPLE)=COUNT BY TO. /* OOPS, won't fly so well... /* The key to solving this is a simple python function in the spssaux library. DATA LIST FREE/ a b c d e f x y z. BEGIN DATA 5 5 5 5 5 5 5 5 5 END DATA. BEGIN PROGRAM. import spssaux varlist=spssaux.VariableDict().expand('a TO z') print varlist END PROGRAM. /* This returns us a python list object. /* ['a', u'b', u'c', u'd', u'e', u'f', u'x', u'y', 'z'] /* Now this is not immediately useful to us in the list format. /* A simple solution is to use the python join function. BEGIN PROGRAM. import spssaux varlist=spssaux.VariableDict().expand('a TO z') print varlist joined=" ".join(varlist) print joined END PROGRAM. /* ['a', u'b', u'c', u'd', u'e', u'f', u'x', u'y', 'z'] /* a b c d e f x y z /* Of course this can be done in a single line of code BEGIN PROGRAM. import spssaux print " ".join(spssaux.VariableDict().expand('a TO z')) END PROGRAM. /* a b c d e f x y z /* To make this useful we can embed this is a python function and pass arguments . BEGIN PROGRAM. import spssaux def myfunction (myvarlist): print " ".join(spssaux.VariableDict().expand(myvarlist )) END PROGRAM. BEGIN PROGRAM. myfunction (myvarlist='a TO z') END PROGRAM. /* So we have the basic tools required to resolve TO for use in macros. DEFINE !myMacro ( !POS !CMDEND) ECHO 'INSIDE !myMacro'. ECHO !QUOTE ( !1). !DO !v !IN ( !1) ECHO !QUOTE ( !v). !DOEND !ENDDEFINE. BEGIN PROGRAM. import spssaux import spss def myfunctionX (myvarlist): spss.Submit( '!myMacro ' + " ".join(spssaux.VariableDict().expand(myvarlist ))) END PROGRAM. BEGIN PROGRAM. myfunctionX (myvarlist='a TO z') END PROGRAM. /* Let's take it a step further and pass our macro name as an additional parameter . BEGIN PROGRAM. import spssaux import spss def myfunctionY (mymacro, myvarlist): spss.Submit( mymacro + " " + " ".join(spssaux.VariableDict().expand(myvarlist ))) END PROGRAM. BEGIN PROGRAM. myfunctionY (mymacro='!mymacro',myvarlist='a TO z') END PROGRAM. /* FINALLY, most macros take more than a simple variable list and frequently /* have named rather than positional arguments. DEFINE !TestVarlist (VariableList !CHAREND ("/") /A !CHAREND ("/")/B !CHAREND ("/") /C !CMDEND ) !DO !Var !IN (!VariableList) ECHO !QUOTE (!Var). !DOEND ECHO !QUOTE (!CONCAT ("A=", !A, " B=", !B, " C=",!C)). !ENDDEFINE. BEGIN PROGRAM. def ResolveVarlist (MACROName,VarParam,VarList, MacroArgs): spss.Submit( '%s %s = %s / %s.' %(MACROName, VarParam," ".join( spssaux.VariableDict().expand(VarList) ),MacroArgs)) END PROGRAM. /* The above simply inserts the elements in the comma separated list sequentially into the /* formula '%s %s = %s / %s.'. It will resolve to: /* MACROName VarParam=VarList-expanded- / MacroArgs. DATA LIST FREE/ var1 TO var10. BEGIN DATA 1 2 3 4 5 6 7 8 9 10 END DATA. SET MPRINT ON PRINTBACK ON. BEGIN PROGRAM. import spssaux import spss ResolveVarlist (MACROName='!TestVarlist', VarParam='VariableList', VarList='var1 TO var3 var5 var7 TO var9', MacroArgs='A=what / B=is / C=this') END PROGRAM. /*You can also call the macro from native SPSS code using: */ !TestVarlist VariableList=var1 var2 var3 var5 var7 var8 var9 / A=what / B=is / C=this . /* The following business simply generalizes these ideas to support multiple arbitrary lists */. DEFINE !MyMacro (VarList1 !CHAREND("/") /VarList2 !CHAREND("/") /A !CHAREND("/") /B !CHAREND("/") /C !CHAREND("/") /D !CMDEND) ECHO "Inside of Macro !MyMacro". ECHO !QUOTE(!CONCAT("VarList1=",!VarList1)). !DO !V !IN (!VarList1) ECHO !QUOTE(!V). !DOEND ECHO !QUOTE(!CONCAT("VarList2=",!VarList2)). !DO !V !IN (!VarList2) ECHO !QUOTE(!V). !DOEND ECHO !QUOTE (!CONCAT ("A=", !A, " B=", !B, " C=",!C, " D=",!D)). !ENDDEFINE. BEGIN PROGRAM. def py_InvokeMacroWithMultipleVariableLists (MacroName,VariableLists,OtherParameters ): SPSScode=MacroName for list in VariableLists.split(","): parts=list.split("=") SPSScode += " ".join([' ',parts[0],'='," ".join(spssaux.VariableDict().expand(parts[1])),'/']) spss.Submit( SPSScode + OtherParameters) print 'Back home in py_InvokeMacroWithMultipleVariableLists' END PROGRAM. MATRIX. SAVE {1:10}/OUTFILE * /VARIABLES var1 TO var10. END MATRIX. BEGIN PROGRAM. import spssaux import spss print 'Prior to function call' py_InvokeMacroWithMultipleVariableLists ( MacroName='!MyMacro', VariableLists='VarList1=var1 TO var3 var5,\ VarList2=var5 var7 TO var9', OtherParameters='A=what /B=a /C=cool /D=trick') print 'All the way back' END PROGRAM. OUTPUT: Inside of Macro !MyMacro VarList1=var1 var2 var3 var5 var1 var2 var3 var5 VarList2=var5 var7 var8 var9 var5 var7 var8 var9 A=what B=a C=cool D=trick /*Could be invoked natively through: */. !MyMacro VarList1=var1 var2 var3 var5 /VarList2=var5 var7 var8 var9 /A=what /B=a /C=cool /D=trick . ----- Please reply to the list and not to my personal email. Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" -- Sent from: http://spssx-discussion.1045642.n5.nabble.com/ ===================== 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
Please reply to the list and not to my personal email.
Those desiring my consulting or training services please feel free to email me. --- "Nolite dare sanctum canibus neque mittatis margaritas vestras ante porcos ne forte conculcent eas pedibus suis." Cum es damnatorum possederunt porcos iens ut salire off sanguinum cliff in abyssum?" |
Nice post, David. Here are a few additional tips. You can use the spssaux.VariableDict class to make a macro smarter. For example, you might want to exclude string variables from a TO list if it is going to invoke DESCRIPTIVES. The VariableDict constructor allows you to filter a variable list according to various variable properties such as measurement level and variable type. So you could write spssaux.VariableDict(<various filter criteria>).expand(...) whether or not it has a TO list or ALL. Full details on this class can be found by opening the spssaux.py module in any plain text editor and reviewing the comments at the top of the class. For users who don't want to write any Python code at all (but still want to use macro?), you can use the SPSSINC SELECT VARIABLES extension command to create a macro that lists only variables that match various metadata criteria such as patterns in names, variable type, variable level, role, and custom attributes. The macro could be used directly or referenced inside other macro code. From the syntax window you can see the full help for this or other installed extension commands by placing the cursor on an instance of the command and pressing F1 (v23 or later) or by running something like SPSSINC SELECT VARIABLES /HELP. This extension command also has a dialog box interface available from the Utilities menu. On Tue, Nov 7, 2017 at 7:27 AM, David Marso <[hidden email]> wrote: /* Background: One of the more frustrating things about SPSS Macro -- |
Free forum by Nabble | Edit this page |