Compute Statistics PSPP Doesn't Provide by Using MATRIX

PSPP is a free statistical program that can do matrix math.

PSPP includes a MATRIX sub-language available in psppire's Syntax Editor window and in the command line pspp program. MATRIX provides a compact environment for numerical computation, making it useful for deriving custom statistics that PSPP does not provide directly.

This sub-language is also useful for learning matrix math and linear algebra. It provides enough functionality needed to compute many college-level assignments and for experimenting with algorithms step-by-step.

PSPP Matrix Capabilities

The PSPP MATRIX sub-language is a general matrix computation and programming environment. It supports control flow (DO IF, ELSE IF, ELSE, END IF, LOOP, BREAK) and numerical operations such as modular arithmetic (MOD). It provides matrix algebra (addition, subtraction, multiplication, transposition via TRANSPOS, inversion via INV and GINV) and advanced linear-algebra routines including singular value decomposition (CALL SVD), Cholesky factorization (CHOL), solving linear systems (SOLVE), and computing eigenvectors and eigenvalues (CALL EIGEN).

It operates independently of the active dataset. Instead of working with variables and cases, it works directly with matrices, including row vectors, column vectors, and scalars. Only short strings (8 bytes) are supported. A "variable" is simply an object created with COMPUTE, and indexing uses parentheses rather than square brackets.

Note: PSPP has the FLIP command that transposes variables and cases but that works on the active data set. It is not a MATRIX command like TRANSPOS or T, which switch rows and columns within the MATRIX environment.

How to Create Matrices

Matrices can be created in several ways. The most common is using GET to pull variables from the active dataset into MATRIX. Matrices can also be created directly inside the MATRIX block using COMPUTE, or read from external files using READ. PSPP also provides a separate MATRIX DATA procedure that defines a matrix using inline numeric data between BEGIN DATA and END DATA. Unlike COMPUTE or READ, MATRIX DATA is a top-level command and cannot be placed inside a MATRIX block.

How to Use MATRIX Inside PSPP

Although MATRIX is designed for matrix algebra, some programs use it primarily for scalar arithmetic. PSPP treats scalars as 1x1 matrices, so functions such as NROW(), MOD(), ABS(), arithmetic operators, relational operators, and branching constructs all work naturally on scalar values. In practice, MATRIX often serves as a compact procedural language for computing custom statistics, even when the calculations involve only simple scalars rather than full matrix operations.

This is the process we'll use:

matrix process

Here, I'll do three short PSPP MATRIX examples: a trimmed mean program, a median absolute deviation (MAD) program, and operating on a full matrix. They are not very long, but make good examples and allow hand computation. They are intended to introduce you to the PSPP MATRIX sub-language and show some useful computation.

In the trimmed-mean and MAD examples below, MATRIX is used mainly for scalar computations: determining indices, computing medians, evaluating conditions, and performing loops. The only true matrix operations are reading a column vector with GET, slicing it with indexing, and summing it with CSUM(). This illustrates how MATRIX can be used effectively even when the underlying computation is not inherently matrix-based.

How to Compute a Trimmed Mean

The trimmed mean is a robust measure of central tendency. Instead of using all values, a trimmed mean removes a fixed percentage of the smallest and largest observations and computes the mean of the remaining data. This reduces the influence of outliers and produces a more stable estimate of the "typical" value when the dataset contains extreme observations.

In this example, 20% of the values are trimmed–10% from the low end and 10% from the high end. The MATRIX program sorts the data, determines how many values to trim, slices the vector accordingly, and computes the mean of the trimmed subset.

Results:
Reading free-form data from INLINE.
+--------+------+
|Variable|Format|
+--------+------+
|x       |F8.0  |
+--------+------+

Value of k
  1

Value of start
  2

Value of end 
  8

Sorted data
   10
   12
   13
   14
   15
   16
   17
   19
  100

Trimmed data
  12
  13
  14
  15
  16
  17
  19

Trimmed mean
 15.1428571429

Here, k determines the 20% number of values to remove, start gives the starting index in the vector, and end gives the ending index. Thus we remove the 10 and the 100 from the data and then compute the mean.

MATRIX Syntax:
DATA LIST LIST /x .
BEGIN DATA
10
12
13
14
14
16
17
19
100
END DATA.

SORT CASES BY x.

MATRIX.
    GET x.

    COMPUTE k = TRUNC(0.20 * NROW(x)).
    COMPUTE start = k + {1}.
    COMPUTE end = NROW(x) - k.
    PRINT k /TITLE="Value of k".
    PRINT start /TITLE="Value of start".
    PRINT end /TITLE="Value of end".

    COMPUTE x_trim = x(start:end) .

    COMPUTE tmean = CSUM(x_trim) / NROW(x_trim).

    PRINT x /TITLE="Sorted data".
    PRINT x_trim /TITLE="Trimmed data".
    PRINT tmean /TITLE="Trimmed mean".
END MATRIX.

This program shows several things:

  1. DATA LIST LIST was used to read the data and make it available to the matrix language.
  2. Selecting values from a matrix uses parentheses for indexing instead of square brackets.
  3. To sum data in pspp matrix, you use RSUM, CSUM, or MSUM. Since we are reading a vertical vector of values, CSUM was used.
  4. To create "variables" use COMPUTE. You can't just assign to variable names directly.
  5. The NROW() matrix function is used to count the rows.
  6. 0.20 is used as the percentage of values to trim from the data, split equally between beginning and end of the data.

Next, a MATRIX program for computing Median Absolute Deviation is shown.

How to Compute Median Absolute Deviation (MAD)

The median absolute deviation (MAD) is a robust measure of spread that uses absolute deviations from the median, making it resistant to outliers.

The data represent wait times at a customer service desk. Most issues appear to be solved in a few minutes, but one person spent over half an hour at the desk. Thus our data has a large outlier which would influence the computation of mean.

This example computes the strict definition of MAD and not the SD-scaled version, which multiplies the MAD value by 1.4826 to make it consistent with the standard deviation under normality. The program as shown outputs the unscaled MAD value; modifying it for the SD-scaled version should be easy if you need it.

This uses DATA LIST FREE to read the data. After the data are read, the values that we don't need (like -1) are removed. Then the cases are sorted for computing the median value. This program checks to see if we have and even number of row or odd numbers of row values and then computes the median based on that with basic math. Function used include MOD(), NROW(), and ABS(). There is no matrix sort that we can use so a bubble sort is added to the program.

Results:
Median Wait Time (6+4/2 = 5 for 9 values once the -1 is removed)
  5

Median Absolute Deviation (MAD)
  1
MATRIX Syntax:
DATA LIST FREE /wait.
BEGIN DATA
4 5 6 5 4 6 5 5 -1 32
END DATA.

* Remove walk-offs (-1).
SELECT IF wait <> -1.

* Sort wait times.
SORT CASES BY wait.

MATRIX.
    GET wait /VARIABLES=wait.

    COMPUTE n = NROW(wait).

    * Determine odd/even sample size.
    COMPUTE is_even = (MOD(n,2) = 0).

    * Median calculation.
    DO IF is_even = 1.
        COMPUTE med = (wait(n/2) + wait(n/2 + 1)) / 2.
    ELSE.
        COMPUTE med = wait((n+1)/2).
    END IF.

    * Absolute deviations.
    COMPUTE dev = ABS(wait - med).

    * Bubble sort deviations.
    LOOP i = 1 TO n-1.
        LOOP j = 1 TO n-i.
            DO IF dev(j) > dev(j+1).
                COMPUTE temp = dev(j).
                COMPUTE dev(j) = dev(j+1).
                COMPUTE dev(j+1) = temp.
            END IF.
        END LOOP.
    END LOOP.

    * MAD calculation with odd/even branching.
    COMPUTE is_even_dev = (MOD(n,2) = 0).

    DO IF is_even_dev = 1.
        COMPUTE mad = (dev(n/2) + dev(n/2 + 1)) / 2.
    ELSE.
        COMPUTE mad = dev((n+1)/2).
    END IF.

    PRINT med /TITLE="Median Wait Time".
    PRINT mad /TITLE="Median Absolute Deviation (MAD)".
END MATRIX.

Verifying PSPP MAD Results

Independent numberical tools or external calculations were used only to validate that the PSPP MATRIX implementation produces the correct strict MAD value. They are included here for completeness and transparency. PSPP users do not need these external tools—the MATRIX program shown above computes the strict MAD directly.

I. Independent verification code:

mad(c(4,4,5,5,5,5,6,6,32))
x <- c(4, 4, 5, 5, 5, 5, 6, 6, 32)
median(abs(x - median(x)))

Output:

> median(abs(x - median(x)))
[1] 1

II. Independent verification code:

import numpy as np

x = np.array([4, 4, 5, 5, 5, 5, 6, 6, 32])
mad_strict = np.median(np.abs(x - np.median(x)))
print(mad_strict)

Output:

1.0

III. Independent verification code:

data x;
  input value;
  datalines;
  4
  4
  5
  5
  5
  5
  6
  6
  32
  ;
run;

/* Compute median */
proc sql noprint;
  select median(value) into :med from x;
  quit;

  /* Compute absolute deviations */
data dev;
  set x;
  absdev = abs(value - &med);
run;

/* Compute strict MAD (median of abs deviations) */
proc sql noprint;
  select median(absdev) into :mad from dev;
  quit;

  %put Strict MAD = &mad;

Output:

100        %put Strict MAD = &mad;
 Strict MAD =        1

How to Use Full Matrices -- Example

Up to this point the examples have been run from vector data. Now we try a small full matrix example with a matrix operation that you probably expected (inverse). Note that to create B below the COMPUTE command is needed. The following was run in the psppire GUI on Windows 11.

MATRIX Syntax:

DATA LIST LIST /x y.
BEGIN DATA
1 2
3 4
END DATA.

MATRIX.
    GET A /VARIABLES=x y.
    COMPUTE B = INV(A).
    PRINT B.
END MATRIX.

Results:

DATA LIST LIST /x y.
Reading free-form data from INLINE.
╭────────┬──────╮
│Variable│Format│
├────────┼──────┤
│x       │F8.0  │
│y       │F8.0  │
╰────────┴──────╯
BEGIN DATA
1 2
3 4
END DATA.

MATRIX.
    GET A /VARIABLES=x y.
    COMPUTE B = INV(A).
    PRINT B.
    COMPUTE C = INV(B).
    PRINT C.
B
 -2.0000000000  1.0000000000
  1.5000000000  -.5000000000

C
  1.0000000000  2.0000000000
  3.0000000000  4.0000000000
END MATRIX.

Note that we get back the original matrix if the first inversion is inverted.

These examples demonstrated how PSPP's MATRIX facility can be used to compute custom statistics using scalar arithmetic, branching, and matrix operations. Users can adapt these patterns to implement trimmed means, percentiles, quartiles, and other robust statistics like median absolute deviation (MAD).

For additional reference, the PSPP User Manual includes a full section on the MATRIX sub-language, covering matrix, matrix data, matrix files, and mconvert.


If you have suggestions, comments, or corrections, you can open an issue on the Github repository Issues list