I find it useful sometimes to do immediate calculations when I am in an interactive data analysis session. In either the R or Stata statistical program, this is as simple as evaluating a valid expression. For an example, typing 8762 - 4653
into the R console will return the result of the expression, 4109
. SPSS does not come out of the box with this functionality, but I have attempted to replicate it utilizing the PRINT
command with temporary variables, and wrap it up in a MACRO for easier use.
The PRINT
command can be used to print plain text output, and takes active variables in the dataset as input. For instance in you have a dataset that consists of the following values;
***************************.
data list free / V1 (F2.0) V2 (F2.0) V3 (A4).
begin data
1 2 aaaa
3 4 bbbb
5 6 cccc
end data.
dataset name input.
dataset activate input.
***************************.
If you run the syntax command
***************************.
PRINT /V1.
exe.
***************************.
The resulting text output (in the output window) will be (Note that for the PRINT
command to route text to the output, it needs to be executed);
1
3
5
Now, to make my immediate expression calculator to emulate R or Stata, I do not want to print out all of the cases in the active dataset (as the expression will be a constant, it is not necessary or wanted). So I can limit the number of cases on the PRINT
command by using a DO IF
and using the criteria $casenum = 1
($casenum
is an SPSS defined variable referring to the row in the dataset). One can then also calculate a temporary variable (represented with a # in the prefix of a variable name) to pass the particular expression to be printed. The below example evaluates 9**4
(nine to the fourth power);
***************************.
DO IF $casenum = 1.
compute #temp = 9**4.
PRINT /#temp.
END IF.
exe.
***************************.
Now we have the ability to pass an expression and have the constant value returned (as long as it would be a valid expression on the right hand side of a compute statement). To make this alittle more automated, one can write a macro that evaluates the expression.
***************************.
DEFINE !calc (!POSITIONAL !CMDEND).
DO IF $casenum = 1.
compute #temp = !1.
PRINT /#temp.
END IF.
exe.
!ENDDEFINE.
!calc 11**5.
***************************.
And now we have a our script that takes an expression and returns the answer. This isn’t great when the number of cases is humongous, as it still appears to cycle through all of the records in the dataset, but for most realisitic sized datasets this calculation will be instantaneous. For a test on 10 million cases, the result was returned in approximately two seconds on my current computer, but the execution of the command took another few seconds to cycle through the dataset.
Other problems with this I could see happening are you cannot directly control the precision with which the value is returned. It appears the temporary variable is returned as whatever the current default variable format is. Below is an example in syntax changing the default to return 5 decimal places.
***************************.
SET Format=F8.5.
!calc 3/10.
***************************.
Also as a note, you will need to have an active dataset with at least one case within it for this to work. Let me know in the comments if I’m crazy and there is an obviously easier way to do this.
Tom Gallacher (@TomWSGallacher)
/ October 17, 2018this really helped, I wanted to do exactly this, just get SPSS to do a basic calculation. I think it could be optimised by rather than “do if” have a “temp. select if”:
DEFINE !calc (!POSITIONAL !CMDEND).
temp.
select if $casenum = 1.
compute #temp = !1.
PRINT /#temp.
exe.
!ENDDEFINE.
Or, a trick I’m finding quite resilient for fooling SPSS to behave is to have a “data list file” point to a .txt with a single digit in it, which means you don’t need a dataset.
DEFINE !calc2 (!POSITIONAL !CMDEND).
data list file=”{txt filepath}” NOTABLE /foo (F1.0) .
compute #temp = !1.
PRINT /#temp.
exe.
!END DEFINE.
Tom Gallacher (@TomWSGallacher)
/ October 17, 2018nuts. last line should be !ENDDEFINE cos duh.