Administrator
|
For reasons I can't disclose in any great detail I have come across the need to !gasp! dig into that beast called python. So far I love it but I only have time to learn just enough to slay this dragon.
I have already developed some well behaved macro code which would be a real PIA to completely port to python. The following demonstrates handing several list objects to python and python parsing them out using a function (upk) I wrote to unpack the list and build a concatenated string followed by a '/' and sending them to an SPSS macro. I'm sure there must exist a built in equivalent to upk? I was thinking of .split followed by .join but apparently a list doesn't have a split method ;-((( The primary motivation for this was the sudden nightmare I discovered when trying to do something like this in SPSS Macro (AFAICT the macro processor is building all 320K blocks of shit before doing anything because it just sits there). DEFINE !BloodyHell (!POS !TOKENS(1) / !POS !TOKENS(1) ) !DO !c = 1 !TO !1 !DO !I = 1 !TO !2 !BoinkMeInTheButt !DOEND !DOEND * This literally sat for a half hr or more before I just PNUKED it !BloodyHell 320 1000 . So, the thought is to resolve all of the loop business in python and call the !BoinkMeInTheButt in the inner loop to avoid the infernal macro processor overhead. Makes complete sense to me and I think I can make this punk work for me and it is likely to be VERY FAST in comparison to other things I've tried this week (F'ng IMPUTE MISSING + SPLIT FILE *BUG*). If anyone (pythonistas ding ding ding) has a more elegant strategy please post to this thread. So far I am enjoying the experience (despite major sleep deprivation) . One thing I am NOT fond of is the use of white space to delineate blocks and the case SeNsItIviTY. I'm sure I'll get used to it. Meanwhile: I think these two might bear a healthy litter of slightly deformed babies over time ;-)) The reason I call this 'A marriage made in hell' is because this week has been a COMPLETE HELL!! DEFINE !SPSSMacro ( a !CHAREND("/") / b !CHAREND("/") / c !CHAREND("/") / d !CHAREND("/")) ECHO !QUOTE(!a). ECHO !QUOTE(!b). ECHO !QUOTE(!c). ECHO !QUOTE(!d). !ENDDEFINE. BEGIN PROGRAM. def upk (listobject): res="" for value in listobject: res=res + str(value) + " " return res + '/' def main ( a,b,c,d, MacroName): import spss spssString =MacroName + ' ' + 'a=' + upk(a) + 'b=' + upk(b) + 'c=' + upk(c) + 'd=' + upk(d) + '.' import spss spss.Submit (spssString) END PROGRAM. SET MPRINT ON PRINTBACK ON. BEGIN PROGRAM. main (a= [1 , 2 , 3 , 4], b=[5 ,6, 7, 8], c= [9, 10, 11, 12] ,d=[13,14,15,16], MacroName ='!SPSSMacro ' ) END PROGRAM.
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?" |
Ok? Here is how I would write the upk function - also you can move the import statements outside of the function call. There is not anything else I would do differently though off-hand with this description.
*****************************************************************. DEFINE !SPSSMacro ( a !CHAREND("/") / b !CHAREND("/") / c !CHAREND("/") / d !CHAREND("/")) ECHO !QUOTE(!a). ECHO !QUOTE(!b). ECHO !QUOTE(!c). ECHO !QUOTE(!d). !ENDDEFINE. BEGIN PROGRAM. import spss def upk(x): x2 = [str(i) for i in x] return ' '.join(x2) + " /" def main(a,b,c,d,MacroName): spssString=MacroName + ' ' + ' a= ' + upk(a) + ' b= ' + upk(b) + ' c= ' + upk(c) + ' d= ' + upk(d) + '.' print "Macro Call: " + spssString spss.Submit(spssString) END PROGRAM. BEGIN PROGRAM. main(a=[1,2,3,4],b=[5,6,7,8],c=[9,10,11,12],d=[13,14,15,16],MacroName='!SPSSMacro') END PROGRAM. *****************************************************************. The !BloodyHell macro works for me with 99 and 99 just echoing the inputs. |
Administrator
|
Thanks Andy,
That is syntactically elegant! Another riddle if you don't mind: Imagine main(a=['1,2', '3,4', '5,6', '7,8' ],b=[5,6,7,8],c=[9,10,11,12],d=[13,14,15,16],MacroName='!SPSSMacro') has to return with a='1 2' '3 4' '5 6' '7 8' / b , c d as before (ie I need to have quoted pairs in a). I hacked it but want elegant. Maybe another parameter for enclose or something? David
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?" |
Administrator
|
In reply to this post by Andy W
"The !BloodyHell macro works for me with 99 and 99 just echoing the inputs. "
What happens if you give it 340 1000? Mine just sits there . Big difference in order of magnitude ~10000 vs 340,000
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?" |
Administrator
|
This post was updated on .
In reply to this post by David Marso
Actually I need a=['1 2','3 4', '5 6' ,'7 8].
I think I have something. EDIT: Blending your elegant loop in the bracket with my earlier thought: passing a string to enclose the parsed atom ;-) Not bad considering I just started digging into python yesterday at about noon with no sleep on Wed ;-) Is it possible to have e be optional so I could do my build as: I would rather not have to create another function upkq (unpackquote). spssString =MacroName + ' ' + 'a=' + upk(a,'"') + 'b=' + upk(b) + 'c=' + upk(c) + 'd=' + upk(d) + '.' -- BEGIN PROGRAM. def upk(x,e): x2 = [e+str(i)+e for i in x] return ' '.join(x2) + " /" def main ( a,b,c,d, MacroName): import spss spssString =MacroName + ' ' + 'a=' + upk(a,'"') + 'b=' + upk(b,'') + 'c=' + upk(c,'') + 'd=' + upk(d,'') + '.' spss.Submit (spssString) END PROGRAM.
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?" |
In reply to this post by David Marso
Agree with Andy in re-writting upk function. I would take it a step further and suggest it's an overkill for something which is so easily done in python, to build a specfic function for. Throwing in a slight variation, call it almost a one liner. BEGIN PROGRAM. import spss def main(a,b,c,d,MacroName): spssString=MacroName + " / ".join( [ " %s=%s " % (i, ' '.join([str(x) for x in j]) ) for i,j in zip(["a","b","c","d"], [a,b,c,d]) ]) print "Macro Call: " + spssString spss.Submit(spssString) END PROGRAM. On Fri, 17 Jun 2016 at 16:18 David Marso <[hidden email]> wrote: "The !BloodyHell macro works for me with 99 and 99 just echoing the inputs. " |
Administrator
|
Thanks Jignesh, Understand that I am in my second day of f'ing around with python and have a harsh deadline. I suppose after an hr of studying your function I would grok it and make that pattern part of my arsenal. However every minute matters at the moment. But Thanks for thinking about my little problem. Give me a month and I'll be pretty proficient but will still likely use macros for main SPSS code and use python as a logic control. Frankly I find huge blocks of shit inside spss.Submit to be difficult to read. Simpler IMNSHO to have the SPSS Block in a DEFINE !ENDDEFINE and have the Submit be a one liner .
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?" |
In reply to this post by David Marso
The upk function can be written more simply as def upk(listobject): return " ".join(str(item) for item in listobject) +"/" The argument to join is a generator expression, which is similar to a Python list comprehension but usually more efficient. It's essentially a compressed form of a for loop. You can create the macro more directly using spss.SetMacroValue(macroname, "macro code") No need for the multiple import spss lines, although it is harmless since Python will ignore the second one. This expression is hard to read. spssString =MacroName + ' ' + 'a=' + upk(a) + 'b=' + upk(b) + 'c=' + upk(c) + 'd=' + upk(d) + '.' It would be more readable if written with parameter substitution, e.g., spssString = """%s a=%s b=%s c=%s d=%s.""" % (MacroName, upk(a), upk(b), upk(c), upk(d)) if I've parsed the string correctly. But using the api call mentioned above would simplify it further. Notice the use of triple quotes to surround the literal. Not necessary here, but if you are generating blocks of Statistics code, using them is good practice because it lets literals span lines, and it allow the use of quotes of either kind within the body. When I first learned Python more than 10 years ago, the use of indentation to define block structure seemed weird, but I've come to love it, because (a) the code is less cluttered, and (b), it works the way it looks (in contrast to the C problem where this isn't always the case). On Fri, Jun 17, 2016 at 7:45 AM, David Marso <[hidden email]> wrote: For reasons I can't disclose in any great detail I have come across the need |
Administrator
|
Thank You Jon, Andy and Jignesh for helping me to cross the python bridge.
I knew there had to be something more elegant than the *CRAP* I posted ;-) For extensive SPSS code I will likely still have MACROS as the workhorse and use Python for feeding them and controlling flow and at any time metadata are required. I learned A LOT today ;-) BTW Jon: The comments at the bottom were VERY helpful in understanding the code!! -- def upk(listobject): return " ".join(str(item) for item in listobject) +"/" I LOVE IT! Very concise! It would be more readable if written with parameter substitution, e.g., spssString = """%s a=%s b=%s c=%s d=%s.""" % (MacroName, upk(a), upk(b), upk(c), upk(d)) That one too. I have my beast slogging away right now. and a panicked Dissertation person pining for a runnable solution. I may slip these in and test them. If they work I'll use them. On the face of it they will be golden. Thanks
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?" |
Free forum by Nabble | Edit this page |