A multiple-linear-regression study that builds an explanatory model for Vodafone's share price (VOD) using a basket of other LSE-listed stocks as predictors. The focus is on the variable-selection workflow: screening for multicollinearity, applying leaps/stepwise/forward/backward selection, Box-Cox response transforms, and residual diagnostics.
Despite the repo name, this is not a time-series forecasting project — it is an explanatory regression study. The original 2023 coursework used an LSE basket supplied with the assignment; that file is no longer available, so the analysis now runs on a clearly-labelled synthetic dataset with the same schema.
.
├── report/
│ └── stock-regression-analysis.Rmd # main write-up (renders to PDF)
├── R/
│ └── stock-regression-analysis.R # same analysis as a sourced script
├── data/
│ ├── generate_demo_data.R # generate the synthetic lse dataset
│ └── README.md # synthetic-data notes + schema
└── output/
├── stock-regression-analysis.pdf # rendered report
└── figures/ # key charts exported as PNG
# R 4.x with: install.packages(c("car","leaps","MASS","corrplot","GGally","ggpubr","broom","tidyverse","rmarkdown"))
Rscript data/generate_demo_data.R # one-off data generation
Rscript -e 'rmarkdown::render("report/stock-regression-analysis.Rmd")'
open output/stock-regression-analysis.pdf-
Multicollinearity screening — correlation matrix, scatterplot
inspection, pruning of redundant predictors (
EXPN,SVT,SMT,Year). -
Transformations — log transforms on
SSE,LLOY,ABFto linearise their relationship with VOD. - Variable selection — leaps-and-bounds, stepwise (both), forward, and backward selection compared head-to-head.
-
Response transforms — Box-Cox identifies
$\lambda \approx 2.6$ –$2.8$ on VOD; the selection process is re-run on the transformed response. -
Residual diagnostics — the standard
lmplot panel, residual ACF, and PRESS statistic.
The residuals are strongly autocorrelated, which is the expected consequence of fitting OLS to price levels. The in-sample fit numbers look impressive (adj-$R^2 \approx 0.91$) but the standard errors are underestimated. A proper analysis would model returns (or log-returns) directly, or use an ARIMAX / dynamic regression. This project documents the workflow rather than claiming a real forecasting result.
| # | Original | Fixed |
|---|---|---|
| 1 | Backward fit referenced data = lsenew4 inside the subset() call that defined lsenew4 (lazy-eval quirk) |
Build the data frame first, then fit |
| 2 | for (i in x){ x <- c(...) } reassigned the loop variable inside its own body |
Plain for (v in candidate_vars) loop |
| 3 | Hard-coded column indices lsenew[,-c(2,8,13,15)] left undocumented |
Annotated in comments |
This is a learning exercise. Nothing here is investment advice.


