Deprecated: Function set_magic_quotes_runtime() is deprecated in /home/mwexler/public_html/tp/textpattern/lib/txplib_db.php on line 14
The Net Takeaway: SPSS and Python: Passing Parameters to Scripts

OTHER PLACES OF INTEREST

Danny Flamberg's Blog
Danny has been marketing for a while, and his articles and work reflect great understanding of data driven marketing.

Eric Peterson the Demystifier
Eric gets metrics, analytics, interactive, and the real world. His advice is worth taking...

Geeking with Greg
Greg Linden created Amazon's recommendation system, so imagine what can write about...

Ned Batchelder's Blog
Ned just finds and writes interesting things. I don't know how he does it.

R at LoyaltyMatrix
Jim Porzak tells of his real-life use of R for marketing analysis.

 

HOW DID YOU GET HERE?

nettakeaway.com
https:
https:
https:
https:
nettakeaway.com
https:
https:
https:
nettakeaway.com

 

 

 

SPSS and Python: Passing Parameters to Scripts · 06/24/2008 11:48 AM, Analysis

UPDATE 6/24/2008: An anonymous source wrote in to let me know that v17 should provide a way to pass simple parameters ala the old way with the Script command.

Meanwhile, the unstoppable Jon Peck of SPSS saw my post and suggested an alternative that is more complicated, but demonstrates some powerful stuff. It also allows for the passing of more sophisticated objects, in case you need to pass a list or something. The nice thing about this approach is that it doesn’t need to read or write files or any other platform dependency, so it can work on all systems.

It has a few pieces, and I’ll show you how they work. Basically, we use an SPSS program to set up the parameters we want to pass, then we call a “helper” program to pass them. The real script we want to run is run, in effect, by the helper. You don’t need to worry about any of that if you want; just use my sample you you can ignore the details. If you want to know more about how Python works, however, dig into Jon’s script.

The first piece is scriptwparams.py, which should also soon show up on the SPSS DevCentral Downloads area (annoying free login required). I give the code below, but treat it as a black box for the moment. You would put it in your favorite Script hangout so it can be “imported” in a Python program.

So, here’s a hypothetical SPSS syntax file. In it, we run a quick freq on a sample dataset, we import this handy “utility script” for passing params I mentioned earlier, then we tell it:

Finally, we tell it to run the script by calling a function in the “helper” program, scriptwparams.runscript().

The result of all this is put the parameters in a “shared memory” area, and then call the the real script.


get file="c:/spss16/samples/cars.sav".

FREQ origin year.
begin program. import spss, spssaux import scriptwparams scripttorun = "c:/python25/lib/site-packages/misc/tests/parampasserscript.py" parms = {"outlinetitle":"Frequency Table", "replacement": "Table of Frequencies"} scriptwparams.runscript(script, params=parms) end program.

Ok, so what about the receiver? Remember, the whole point was to pass some parameters TO our script. Well, our script, using the same “helper file”, can now read from that shared memory area and then do what we need by parsing the parameters.

In this case, our simple little “parampasserscript.py” reads the parameters, starts reading the output tree, and if the outline title matches what we passed in, it changes it to the replacement we passed in (see the SPSS syntax above). Simple, but the point is that we passed in 2 pieces of info: what to search for, and what to replace with.

parampasserscript.py


#script with parameters
#run the procedure named in the procedure parameter on the variable named in the variable parameter
import SpssClient, scriptwparams
SpssClient.StartClient()
parms = scriptwparams.getscriptparams()
doc = SpssClient.GetDesignatedOutputDoc()
items = doc.GetOutputItems()
for index in range(items.Size()):
    item = items.GetItemAt(index)
    if item.GetDescription() == parms['outlinetitle']:
        item.SetDescription(parms['replacement'])
SpssClient.StopClient()

Here is Jon’s “helper” script. As I mentioned, I suspect it will wind up on DevCentral, but if you can’t wait, here it is.

scriptwparams.py,


#post parameters for script
import mmap, pickle, os, tempfile, sys
import spss, spssaux
def runscript(scriptname, params={}):
    fn = tempfile.gettempdir() + os.sep + "__SCRIPT__"
    f = file(fn, "w+")
    shmem = mmap.mmap(f.fileno(), 4096, access=mmap.ACCESS_WRITE)
    shmem.write(pickle.dumps(params))
    f.close()
    spss.Submit("SCRIPT " + spssaux._smartquote(scriptname))
    try:
        os.remove(f)
    except:
        pass
def getscriptparams():
    fn = tempfile.gettempdir() + os.sep + "__SCRIPT__"
    try:
        f = file(fn, "r")
        shmem = mmap.mmap(f.fileno(), 4096, access=mmap.ACCESS_READ)
        ps = shmem.read(4096)
        try:
            f.close()
            os.remove(fn)
        except:
            pass
    except:
        return {}
    if ord(ps[0]) == 0:
        return {}
    d =pickle.loads(ps)
    shmem.close()
    return d

Ok, so now, this post shows 2 ways to pass parameters in v16 with a bit of work (this “shared memory” and the simpler temp file creation) along with 2 ways that don’t work but are worth playing with to better understand what’s happening when SPSS calls out to Python.

======Original Post ======

As you may recall, with old Sax Basic, you could do things like:
SCRIPT file=“c:\my documents\ChangeLabelTitle.sbs” (“Freq of Men only”) . And the Script could look at strParam = objSpssApp.ScriptParameter(0) to see it.

But in v16, the Python plugin for SPSSClient Scripts doesn’t seem to pass parameters, which sucks. This is for v16.0.2, perhaps it will get fixed in a later version.

So, using my “change the Label and Title and Header” script, I tried to pass in what I wanted the changed label to be.

I tried 3 work arounds. 1 finally worked, 2 didn’t, but I put it here to save you the pain of wasting your time with these “what ifs”.

1) Run it directly. I tried just calling the Python script directly.
This runs and printed out the debug print statements I included, but it spawns a whole new SPSS unit so the viewer tree doesn’t get touched.


BEGIN PROGRAM PYTHON.
import os, spss
psout = os.popen("C:/Python25/Lib/site-packages/spss160/spss/changetitle.py")
results = psout.read().split('\n')
for line in results:
   print line
END PROGRAM.

2) Ok, fine. Can we make an “environment variable” and pass that down to the spawned process?

Python has things like os.environ to play with the environment, but you guessed it, it doesn’t get carried over to other processes (same for getenv and putenv, for you picky ones). If I really wanted it, I could put it in the registry, but that seems overdoing it.

So, the below ran, but my test program could never see the “changelabel” environment variable.


BEGIN PROGRAM PYTHON.
import os, spss
os.environ['CHANGELABEL'] = 'python env label test'
END PROGRAM.

SCRIPT file="C:\Python25\Lib\site-packages\spss160\spss\test.py" ("Freq of Men only").

3) Sigh. Make a file.

The oldest way, make a file and put what you need into it. SPSS even has an environment variable which points to its temp file, so at least I can hide the file and not litter.

The below code does work, and is the current preferred solution. You’ll need both parts for each use, the file writer and the python script.


BEGIN PROGRAM PYTHON.
import os
tmpfile = open(os.environ['SPSSTMPDIR'] + 'changelabeltemp.txt', 'w')
tmpfile.write('test another new label for python')
tmpfile.flush()
tmpfile.close
END PROGRAM.

SCRIPT file="C:\Python25\Lib\site-packages\spss160\spss\changetitle.py".

then, in external script:


import SpssClient, os
SpssClient.StartClient()
# First, open the file to find out what to change...
thelabel=file(os.environ['SPSSTMPDIR'] + 'changelabeltemp.txt').read()
print thelabel
SpssClient.LogToViewer(thelabel)
# want to change Title, then Heading
objOutputDoc = SpssClient.GetDesignatedOutputDoc()
objOutputItems = objOutputDoc.GetOutputItems()
for index in range(objOutputItems.Size()):
    objOutputItem = objOutputItems.GetItemAt(index)
    if objOutputItem.GetType() == SpssClient.OutputItemType.TITLE:
        # Fix the Title first
        objTitleItem = objOutputItem.GetSpecificType()
        SpssClient.LogToViewer(objTitleItem.GetTextContents())
        objTitleItem.SetTextContents(thelabel)
        objOutputItem.SetDescription(thelabel)
        index = index-1 # Back one for the header...
        objOutputItem = objOutputItems.GetItemAt(index)
        objHeaderItem = objOutputItem.GetSpecificType()
        objOutputItem.SetDescription(thelabel)
print "done!"
# SpssClient.Exit()
SpssClient.StopClient()

Not as easy as the Sax version, but basically delivers the same results.

Well, not quite. For some reason, it keeps showing HTML tags and screwing with the font, making the output look ugly. I’ll keep playing and see if I can solve it.



PS: Note to self: you keep forgetting where these directories are, so here they are.


SPSS160_SCRIPTING_HOME 
C:\Program Files\SPSSInc\SPSS16 
SPSSTMPDIR 
C:\DOCUME~1\username\LOCALS~1\Temp\ 

so don’t forget!

* * *

 

Name
E-mail
http://
Message
  Textile Help
Please note that your email will be obfuscated via entities, so its ok to put a real one if you feel like it...

Admin
powered by Textpattern 4.0.4 (r1956)