2
votes

Let's assume I have two lists of variables

list a: a1 a2 a3
list b: b1 b2 b3

which I want to process in a way like this:

TEMPORARY.
SELECT IF a1=b1.
FREQUENCY someVar.


TEMPORARY.
SELECT IF a2=b2.
FREQUENCY someVar.


TEMPORARY.
SELECT IF a2=b2.
FREQUENCY someVar.

I tried tried to do this within a python loop:

BEGIN PROGRAM.
import spss

la = ['a1', 'a2', 'a3']
lb = ['b1', 'b2', 'b3']

for a, b in zip(la, lb):
    spss.Submit('''
TEMPORARY.
SELECT IF %s=%s.
FREQUENCY someVar.
    ''' % (a, b))
END PROGRAM.

So far so good. This works except when the SELECT IF command would create an empty dataset. Outside the Python program block this would cause the following warning message in the output viewer:

No cases were input to this procedure. Either there are none in the working data file or all of them have been filtered out. Execution of this command stops.

But inside a Python block it causes an Error and the python script to stop.

Traceback (most recent call last):
File "", line 7, in
File "C:\PROGRA~1\ibm\SPSS\STATIS~1\23\Python\Lib\site-packages\spss\spss.py", line 1527, in Submit raise SpssError,error spss.errMsg.SpssError: [errLevel 3] Serious error.

Is there a way to run this loop (which might produce temporary empty data sets and therefore warnings) inside of python?

4

4 Answers

2
votes

Yes, if you wrap the problematic function inside a try-except construct:

for a, b in zip(la, lb):
    try:
        spss.Submit('''
TEMPORARY.
SELECT IF %s=%s.
FREQUENCY someVar.
        ''' % (a, b))
    except:
        pass
2
votes

You could also use Python APIs to calculate how many cases ai=bi and execute conditional blocks according to this.

So for example if only less than 5 valid cases remain you may not want to produce any output (or some output suggesting no output is being produced due to low base sizes). If under 50 cases remain then you may want to run frequencies and if more than 50 cases then run descriptives ect ect. There are a number of ways you get the case count, which approach is best and most efficient perhaps depends on your data set and end goal.

See for example: spss.GetCaseCount

Here's another approach where you can get case count like statistics from active dataset to inspire further ideas.

1
votes

Adding some explanation: Statistics syntax errors have an associated severity level between 1 (lowest) and 5. You will probably never see a 5, because that means that the system has gone down in flames. When running syntax from Python via Submit, level 1 and 2 errors, which are warnings that don't stop the syntax from running, are executed normally. Level 3 and higher raise exceptions. You can handle those in your Python code via the try/except mechanism as was suggested above.

0
votes

I experimented with SET MXWARNS, however neither setting it to zero, nor setting it to a very high value (e.g. 1000000) worked. The warnings were still converted into errors. So I wrote this work-around:

import codecs
import re
import sys

import spss
from spssaux import getShow

def submit_syntax(sps_filename):
    output_on = spss.IsOutputOn()
    spss.SetOutput("off")
    unicode_mode = getShow("unicode") == u"Yes"
    encoding = "utf-8-sig" if unicode_mode else getShow("locale").split(u".")[-1]
    if output_on:
        spss.SetOutput("on")

    with codecs.open(sps_filename, encoding=encoding) as f:
        syntax = f.read()
    statements = re.split(ur"\. *\r\n", syntax, flags=re.MULTILINE)
    for stmtno, statement in enumerate(statements, 1):
        if statement.startswith(u"*"):
            continue
        try:
            spss.Submit(statement)
        except spss.SpssError:
            # "no cases were input" warnings are translated into errors.
            if not spss.GetCaseCount() and spss.GetLastErrorLevel() <= 3:
                continue
            msg = u"ERROR in statement #%d: %s [%s]"
            raise RuntimeError(msg % (stmtno, statement, sys.exc_info()[1]))