This book runs on R, but the ideas are not R’s property. A correlation is a correlation, a regression is a regression, whatever software you type it into. This appendix shows the core procedures from the book side by side in four environments: R, SPSS, Julia, and Python. Click the tabs to switch languages. The R code is live - it runs here and produces the output you see - and the SPSS, Julia, and Python versions produce the same result, written the way each language likes to write it.
We use one small dataset throughout: 80 people in two groups, with a predictor x and an outcome y.
library(tidyverse) # dplyr, ggplot2, purrr, tibble, readr, stringr, forcatslibrary(broom) # tidy(), glance(), augment() for model outputsource("_common.R") # book-wide helpers: round2(), fmt_p(), tidy2()set.seed(1)d <-tibble(group =factor(rep(c("A", "B"), each =40)),x =rnorm(80, mean =50, sd =10)) |>mutate(y =100+0.8* x +rnorm(80, sd =12)) # y depends on xd |>head(3) |>round2()
group
x
y
A
43.74
128.16
A
51.84
139.85
A
41.64
147.45
In SPSS, imagine this same table loaded as the active dataset with variables group, x, and y. In Julia, imagine it as a DataFrame called d. In Python, imagine it as a pandas DataFrame, also called d.
Descriptive Statistics
NoteWorking in SPSS, Julia, or Python?
The code tabs below assume this chapter’s data is already loaded. Grab the one-file setup for your language from Getting the Book’s Data, run it once, then load what you need by name - this chapter uses appendix-d, appendix-items. For example, book_data("appendix-d") in R, Julia, or Python, or !bookdata name = "appendix-d". in SPSS. Every language reads the same shipped files, so your numbers will match the ones printed here exactly.
2×5 DataFrame
Row │ variable mean std min max
│ Symbol Float64 Float64 Float64 Float64
─────┼─────────────────────────────────────────────────
1 │ x 51.0615 9.00817 27.853 74.0162
2 │ y 139.688 11.3229 112.121 168.041
import pandas as pdd = pd.read_csv("data/sim/appendix-d.csv")d[["x", "y"]].describe().loc[["mean", "std", "min", "max"]]
x y
mean 51.061465 139.687859
std 9.008166 11.322888
min 27.853001 112.121409
max 74.016178 168.041449
Two sample t-test (unequal variance)
------------------------------------
Population details:
parameter of interest: Mean difference
value under h_0: 0
point estimate: 4.90085
95% confidence interval: (-0.05031, 9.852)
Test summary:
outcome with 95% confidence: fail to reject h_0
two-sided p-value: 0.0523
Details:
number of observations: [40,40]
t-statistic: 1.9706711481407315
degrees of freedom: 77.86370003535342
empirical standard error: 2.486894871319471
usingCSV, DataFrames, CategoricalArraysd = CSV.read("data/sim/appendix-d.csv", DataFrame)d.group =categorical(d.group)usingGLMm =lm(@formula(y ~ group), d)ftest(m.model) # overall F test for the group effect
F-test against the null model:
F-statistic: 3.88 on 80 observations and 1 degrees of freedom, p-value: 0.0523
import pandas as pdd = pd.read_csv("data/sim/appendix-d.csv")import statsmodels.formula.api as smffrom statsmodels.stats.anova import anova_lmanova_lm(smf.ols("y ~ group", data=d).fit()) # overall F for the group effect
df sum_sq mean_sq F PR(>F)
group 1.0 480.367001 480.367001 3.883545 0.05231
Residual 78.0 9648.047918 123.692922 NaN NaN
# a small item set for the reduction exampleset.seed(2)it <-map(1:4, \(i) rnorm(80) + d$x /10) |>set_names(paste0("item", 1:4)) |>as_tibble()tibble(component =paste0("PC", 1:4),eigenvalue =prcomp(it, scale. =TRUE)$sdev^2) |>round2()
usingCSV, DataFrames, MultivariateStats, Statisticsit = CSV.read("data/sim/appendix-items.csv", DataFrame)# standardise first, so these are eigenvalues of the CORRELATION matrix -# the same thing prcomp(scale. = TRUE) and StandardScaler give the other tabsX =Matrix(it)Z = (X .-mean(X, dims =1)) ./std(X, dims =1)M =fit(PCA, Z'; maxoutdim =4)principalvars(M) # variance along each component
import pandas as pdfrom sklearn.decomposition import PCAit = pd.read_csv("data/sim/appendix-items.csv")# standardise with the SAMPLE sd (n - 1). StandardScaler divides by the# population sd, which would shift every eigenvalue by a factor of n/(n-1)# and quietly disagree with the R and Julia tabs.z = (it - it.mean()) / it.std()PCA().fit(z).explained_variance_ # variance along each component
R is free, open source, and the language this book runs in. Everything you see executes.
SPSS is menu-driven, but every menu click also writes syntax - the code shown above. Pasting that syntax into a Syntax window and running it is the reproducible way to use SPSS, and it reads much like the R.
Julia is free and open source, fast, and increasingly used for heavy Bayesian and simulation work. Its statistics live in packages (Statistics, DataFrames, GLM, HypothesisTests, MultivariateStats), loaded with using.
Python is free and open source, and probably the language your students already know. Data lives in a pandas DataFrame; the models come from statsmodels, whose formula interface (smf.ols("y ~ x", data=d)) reads almost exactly like R’s. scipy.stats supplies the classical tests and scikit-learn the reduction methods.
The point is not that one is best. It is that a procedure you understand in one language you can carry to any of them, because the statistics were never about the software.
Two Ways SPSS Fails Quietly
Most mistakes announce themselves. These two do not, and both cost us a wrong number in this book before we caught them, so they are worth knowing before you write much syntax.
A continuation line that begins with * disappears. In SPSS syntax an asterisk in the command position starts a comment. That is fine on its own line, but it also means a long expression broken across lines like this loses everything after the first line:
COMPUTE total = total + ((-1) ** #i)
* EXP(LNGAMMA(k+1) - LNGAMMA(#i+1) - LNGAMMA(k-#i+1)).
No error appears. The multiplication is simply gone, and you get the value of the first line alone. Break the line so each operator ends its line instead, and the same expression runs correctly:
COMPUTE total = total +
((-1) ** #i) *
EXP(LNGAMMA(k+1) - LNGAMMA(#i+1) - LNGAMMA(k-#i+1)).
/DELIMITERS does not read escape sequences. Writing /DELIMITERS=' \t' to mean “spaces or tabs” gives you spaces, backslashes, and the letter t — because SPSS takes those two characters literally rather than as an escape for a tab. A file whose columns are separated by tabs then loads with no complaint and every value in the wrong variable. Put a real tab character between the quotes. The Rasch chapter reads Wright’s Knox Cube data this way, and the giveaway that something was wrong was an N that varied from item to item when every item had the same 35 responses.
Both share a shape worth carrying with you: the file loaded, the syntax ran, nothing was flagged, and the numbers were wrong. When an SPSS result surprises you, check that the syntax you think you ran is the syntax that actually ran.