This document summarises the forecast outcomes for the second weekly set of forecasts for English football match outcomes, following on from last week, and it provides outcomes for forecasts of matches over the last week as detailed in this document.
Two sets of forecasts are constructed, one using a simple linear regression method for a dependent variable taking the values 0 for an away win, 0.5 for a draw, and 1 for a home win. This linear regression method only yields a number which can be interpreted as a probability of an outcome occurring. The second, ordered logit method, treats each outcome in an ordered manner, from away win, to draw, to home win, and estimates a probability for each outcome.
The purpose of this document is to evaluate these forecasts, and begin to form a longer-term narrative about them.
To consider outcomes; we must load up the specific outcomes file for matches forecast over the weekend:
dates <- c("2015-01-30","2015-02-06","2015-02-13")
date.1 <- dates[NROW(dates)]
recent.forecast.outcomes <- read.csv(paste("forecast_outcomes_",date.1,".csv",sep=""),stringsAsFactors=F)
forecast.matches <- read.csv(paste("forecasts_",date.1,".csv",sep=""))
forecast.matches <- forecast.matches[is.na(forecast.matches$outcome)==F,]
forecast.outcomes <- merge(forecast.matches[,c("match_id","outcome","Ph","Pd","Pa")],
recent.forecast.outcomes,by=c("match_id"),
suffixes=c(".forc",".final"))
forecast.outcomes <- forecast.outcomes[is.na(forecast.outcomes$outcome.final)==F,]
#all.forecast.outcomes <- data.frame()
#for(i in dates) {
# temp.0 <- read.csv(paste(loc2,"forecast_outcomes_",i,".csv",sep=""),stringsAsFactors=F)
# temp.1 <- read.csv(paste(loc2,"forecasts_",i,".csv",sep=""))
# temp.1 <- temp.1[is.na(temp.1$outcome)==F,]
# temp.2 <- merge(temp.1[,c("match_id","outcome","Ph","Pd","Pa")],
# temp.0,by=c("match_id"),
# suffixes=c(".forc",".final"))
# forecast.outcomes <- rbind(temp.2[is.na(temp.2$outcome.final)==F,],forecast.outcomes)
#}
We also load up previous weeks’ forecasts and outcomes in order that we can begin to determine trends over time. This week was one particularly filled with surprise results, but that does not necessarily mean our forecast model need be amended. More, it reflects that football is intrinsically a very uncertain game. This, of course, is not to say that the model cannot be improved upon.
First, our FA Cup forecasts:
facup.matches <- forecast.outcomes[forecast.outcomes$division=="English FA Cup",]
facup.matches$id <- 1:NROW(facup.matches)
par(mar=c(9,4,4,5)+.1)
plot(facup.matches$id,facup.matches$outcome.forc,xaxt="n",xlab="",ylim=range(0,1),
main="Forecasts of Weekend FA Cup Matches",
ylab="Probability of Outcome")
lines(facup.matches$id,facup.matches$Ph,col=2,pch=15,type="p")
lines(facup.matches$id,facup.matches$Pd,col=3,pch=16,type="p")
lines(facup.matches$id,facup.matches$Pa,col=4,pch=17,type="p")
legend("topleft",ncol=4,pch=c(1,15,16,17),col=c(1:4),
legend=c("OLS","OL (home)","OL (draw)","OL (away)"),bty="n")
abline(h=0.5,lty=2)
abline(h=0.6,lty=3)
abline(h=0.7,lty=2)
abline(h=0.4,lty=3)
for(i in 1:NROW(facup.matches)) {
if(facup.matches$outcome.final[i]==1) {
lines(facup.matches$id[i],facup.matches$outcome.final[i],col=2,type="p",pch=0)
lines(rep(i,2),c(facup.matches$Ph[i],facup.matches$outcome.final[i]),type="l",lty=2,col="red")
} else if (facup.matches$outcome.final[i]==0.5) {
lines(facup.matches$id[i],facup.matches$outcome.final[i],col=3,type="p",pch=1)
lines(rep(i,2),c(facup.matches$Pd[i],facup.matches$outcome.final[i]),type="l",lty=2,col="green")
} else {
lines(facup.matches$id[i],facup.matches$outcome.final[i],col=4,type="p",pch=2)
lines(rep(i,2),c(facup.matches$Pa[i],facup.matches$outcome.final[i]),type="l",lty=2,col="blue")
}
}
axis(1,at=facup.matches$id,labels=paste(facup.matches$team1,facup.matches$team2,sep=" v "),las=2,cex.axis=0.65)
Outcomes are hollowed variants of their predicted probabilities; red empty circles are home wins, marked on at 1, green empty circles are draws, marked on at 0.5, and blue empty triangles are away wins. All are linked to their associated probability. This drawing doesn’t quite reflect actual forecast errors since each outcome is 1 if it happened, but nonetheless illustrates the weekend’s outcomes.
The weekend was another one for surprising results in the FA Cup; Blackburn beat Stoke, Bradford beat Sunderland, and to a lesser extent, Reading beat Derby. Furthermore, at least one game expected to be tight was anything but, with West Brom beating West Ham 4-0. The favourites did progress between Arsenal and Middlesbrough, Liverpool and Crystal Palace, Aston Villa and Leicester, and Man United at Preston. Additionally, of course, bookmakers suffered forecast errors this week.
It is worth noting that one of the issues I have identified with these forecasts previously is that they appear somewhat conservative, but when unexpected results do occur, this means forecast errors are smaller.
Next, our Championship forecasts:
champ.matches <- forecast.outcomes[forecast.outcomes$division=="English Championship",]
champ.matches$id <- 1:NROW(champ.matches)
par(mar=c(9,4,4,5)+.1)
plot(champ.matches$id,champ.matches$outcome.forc,xaxt="n",xlab="",ylim=range(0,1),
main="Forecasts of Weekend Championship Matches",
ylab="Probability of Outcome")
lines(champ.matches$id,champ.matches$Ph,col=2,pch=15,type="p")
lines(champ.matches$id,champ.matches$Pd,col=3,pch=16,type="p")
lines(champ.matches$id,champ.matches$Pa,col=4,pch=17,type="p")
legend("topleft",ncol=4,pch=c(1,15,16,17),col=c(1:4),
legend=c("OLS","OL (home)","OL (draw)","OL (away)"),bty="n")
abline(h=0.5,lty=2)
abline(h=0.6,lty=3)
abline(h=0.7,lty=2)
abline(h=0.4,lty=3)
for(i in 1:NROW(champ.matches)) {
if(champ.matches$outcome.final[i]==1) {
lines(champ.matches$id[i],champ.matches$outcome.final[i],col=2,type="p",pch=0)
lines(rep(i,2),c(champ.matches$Ph[i],champ.matches$outcome.final[i]),type="l",lty=2,col="red")
} else if (champ.matches$outcome.final[i]==0.5) {
lines(champ.matches$id[i],champ.matches$outcome.final[i],col=3,type="p",pch=1)
lines(rep(i,2),c(champ.matches$Pd[i],champ.matches$outcome.final[i]),type="l",lty=2,col="green")
} else {
lines(champ.matches$id[i],champ.matches$outcome.final[i],col=4,type="p",pch=2)
lines(rep(i,2),c(champ.matches$Pa[i],champ.matches$outcome.final[i]),type="l",lty=2,col="blue")
}
}
axis(1,at=champ.matches$id,labels=paste(champ.matches$team1,champ.matches$team2,sep=" v "),las=2,cex.axis=0.65)
In the Championship, perhaps the most surprising result was Bournemouth being held at home by Huddersfield.
Next, our League One forecasts:
lg1.matches <- forecast.outcomes[forecast.outcomes$division=="English League One",]
lg1.matches$id <- 1:NROW(lg1.matches)
par(mar=c(9,4,4,5)+.1)
plot(lg1.matches$id,lg1.matches$outcome.forc,xaxt="n",xlab="",ylim=range(0,1),
main="Forecasts of Weekend League One Matches",
ylab="Probability of Outcome")
lines(lg1.matches$id,lg1.matches$Ph,col=2,pch=15,type="p")
lines(lg1.matches$id,lg1.matches$Pd,col=3,pch=16,type="p")
lines(lg1.matches$id,lg1.matches$Pa,col=4,pch=17,type="p")
legend("topleft",ncol=4,pch=c(1,15,16,17),col=c(1:4),
legend=c("OLS","OL (home)","OL (draw)","OL (away)"),bty="n")
abline(h=0.5,lty=2)
abline(h=0.6,lty=3)
abline(h=0.7,lty=2)
abline(h=0.4,lty=3)
for(i in 1:NROW(lg1.matches)) {
if(lg1.matches$outcome.final[i]==1) {
lines(lg1.matches$id[i],lg1.matches$outcome.final[i],col=2,type="p",pch=0)
lines(rep(i,2),c(lg1.matches$Ph[i],lg1.matches$outcome.final[i]),type="l",lty=2,col="red")
} else if (lg1.matches$outcome.final[i]==0.5) {
lines(lg1.matches$id[i],lg1.matches$outcome.final[i],col=3,type="p",pch=1)
lines(rep(i,2),c(lg1.matches$Pd[i],lg1.matches$outcome.final[i]),type="l",lty=2,col="green")
} else {
lines(lg1.matches$id[i],lg1.matches$outcome.final[i],col=4,type="p",pch=2)
lines(rep(i,2),c(lg1.matches$Pa[i],lg1.matches$outcome.final[i]),type="l",lty=2,col="blue")
}
}
axis(1,at=lg1.matches$id,labels=paste(lg1.matches$team1,lg1.matches$team2,sep=" v "),las=2,cex.axis=0.65)
League One added to the theme of unexpected results with all of the top three teams (Swindon, Bristol City and MK Dons) losing.
Next, our League Two forecasts:
lg2.matches <- forecast.outcomes[forecast.outcomes$division=="English League Two",]
lg2.matches$id <- 1:NROW(lg2.matches)
par(mar=c(9,4,4,5)+.1)
plot(lg2.matches$id,lg2.matches$outcome.forc,xaxt="n",xlab="",ylim=range(0,1),
main="Forecasts of Weekend League Two Matches",
ylab="Probability of Outcome")
lines(lg2.matches$id,lg2.matches$Ph,col=2,pch=15,type="p")
lines(lg2.matches$id,lg2.matches$Pd,col=3,pch=16,type="p")
lines(lg2.matches$id,lg2.matches$Pa,col=4,pch=17,type="p")
legend("topleft",ncol=4,pch=c(1,15,16,17),col=c(1:4),
legend=c("OLS","OL (home)","OL (draw)","OL (away)"),bty="n")
abline(h=0.5,lty=2)
abline(h=0.6,lty=3)
abline(h=0.7,lty=2)
abline(h=0.4,lty=3)
for(i in 1:NROW(lg2.matches)) {
if(lg2.matches$outcome.final[i]==1) {
lines(lg2.matches$id[i],lg2.matches$outcome.final[i],col=2,type="p",pch=0)
lines(rep(i,2),c(lg2.matches$Ph[i],lg2.matches$outcome.final[i]),type="l",lty=2,col="red")
} else if (lg2.matches$outcome.final[i]==0.5) {
lines(lg2.matches$id[i],lg2.matches$outcome.final[i],col=3,type="p",pch=1)
lines(rep(i,2),c(lg2.matches$Pd[i],lg2.matches$outcome.final[i]),type="l",lty=2,col="green")
} else {
lines(lg2.matches$id[i],lg2.matches$outcome.final[i],col=4,type="p",pch=2)
lines(rep(i,2),c(lg2.matches$Pa[i],lg2.matches$outcome.final[i]),type="l",lty=2,col="blue")
}
}
axis(1,at=lg2.matches$id,labels=paste(lg2.matches$team1,lg2.matches$team2,sep=" v "),las=2,cex.axis=0.65)
In League Two, again by and large results followed predictions, with the exceptions of Hartlepool’s win over Northampton, and away wins for Carlisle, Plymouth and Dagenham and Redbridge.
Next, our Football Conference forecasts:
conf.matches <- forecast.outcomes[forecast.outcomes$division=="Football Conference",]
conf.matches$id <- 1:NROW(conf.matches)
par(mar=c(9,4,4,5)+.1)
plot(conf.matches$id,conf.matches$outcome.forc,xaxt="n",xlab="",ylim=range(0,1),
main="Forecasts of Weekend Football Conference Matches",
ylab="Probability of Outcome")
lines(conf.matches$id,conf.matches$Ph,col=2,pch=15,type="p")
lines(conf.matches$id,conf.matches$Pd,col=3,pch=16,type="p")
lines(conf.matches$id,conf.matches$Pa,col=4,pch=17,type="p")
legend("topleft",ncol=4,pch=c(1,15,16,17),col=c(1:4),
legend=c("OLS","OL (home)","OL (draw)","OL (away)"),bty="n")
abline(h=0.5,lty=2)
abline(h=0.6,lty=3)
abline(h=0.7,lty=2)
abline(h=0.4,lty=3)
for(i in 1:NROW(conf.matches)) {
if(conf.matches$outcome.final[i]==1) {
lines(conf.matches$id[i],conf.matches$outcome.final[i],col=2,type="p",pch=0)
lines(rep(i,2),c(conf.matches$Ph[i],conf.matches$outcome.final[i]),type="l",lty=2,col="red")
} else if (conf.matches$outcome.final[i]==0.5) {
lines(conf.matches$id[i],conf.matches$outcome.final[i],col=3,type="p",pch=1)
lines(rep(i,2),c(conf.matches$Pd[i],conf.matches$outcome.final[i]),type="l",lty=2,col="green")
} else {
lines(conf.matches$id[i],conf.matches$outcome.final[i],col=4,type="p",pch=2)
lines(rep(i,2),c(conf.matches$Pa[i],conf.matches$outcome.final[i]),type="l",lty=2,col="blue")
}
}
axis(1,at=conf.matches$id,labels=paste(conf.matches$team1,conf.matches$team2,sep=" v "),las=2,cex.axis=0.65)
Numerically it is important to evaluate forecast errors.
For the OLS model:
forecast.outcomes$error <- forecast.outcomes$outcome.final - forecast.outcomes$outcome.forc
forecast.outcomes$error2 <- forecast.outcomes$error^2
forecast.outcomes$aerror <- abs(forecast.outcomes$error)
#summary(forecast.outcomes[forecast.outcomes$tier<=5,c("error","error2","aerror")])
summary(forecast.outcomes[,c("error","error2","aerror")])
## error error2 aerror
## Min. :-0.781856 Min. :0.0000029 Min. :0.001706
## 1st Qu.:-0.491639 1st Qu.:0.0935982 1st Qu.:0.305933
## Median : 0.104093 Median :0.2057101 Median :0.453510
## Mean :-0.004839 Mean :0.2152598 Mean :0.419424
## 3rd Qu.: 0.419604 3rd Qu.:0.3115055 3rd Qu.:0.558110
## Max. : 0.620529 Max. :0.6112989 Max. :0.781856
For the ordered logit we must consider the three outcomes distinctly; for the home win:
forecast.outcomes$error.h <- forecast.outcomes$outcome.final - forecast.outcomes$Ph
forecast.outcomes$error.d <- as.numeric(forecast.outcomes$outcome.final==0.5) - forecast.outcomes$Pd
forecast.outcomes$error.a <- as.numeric(forecast.outcomes$outcome.final==0) - forecast.outcomes$Pa
forecast.outcomes$error.h2 <- forecast.outcomes$error.h^2
forecast.outcomes$error.d2 <- forecast.outcomes$error.d^2
forecast.outcomes$error.a2 <- forecast.outcomes$error.a^2
forecast.outcomes$aerror.h <- abs(forecast.outcomes$error.h)
forecast.outcomes$aerror.d <- abs(forecast.outcomes$error.d)
forecast.outcomes$aerror.a <- abs(forecast.outcomes$error.a)
#summary(forecast.outcomes[forecast.outcomes$tier<=5,c("error","error2","aerror")])
summary(forecast.outcomes[,c("error.h","error.d","error.a")])
## error.h error.d error.a
## Min. :-0.6895 Min. :-0.28221 Min. :-0.49842
## 1st Qu.:-0.3408 1st Qu.:-0.27911 1st Qu.:-0.34131
## Median : 0.2487 Median :-0.25556 Median :-0.19914
## Mean : 0.1286 Mean :-0.09274 Mean : 0.04749
## 3rd Qu.: 0.5624 3rd Qu.:-0.22814 3rd Qu.: 0.62262
## Max. : 0.7603 Max. : 0.80956 Max. : 0.87636
Considering here just the mean errors, the forecasts for home wins were biased downward much more than those for either the draw or away win; a positive forecast error suggests that the event occurs more often than the model predicts. Until we consider more forecasts, it is difficult to say whether this is simply an artifact of one particular week.
We can consider also, by division, forecast errors:
library(knitr)
aggs <- aggregate(forecast.outcomes[,c("error","error2","aerror")],
by=list(forecast.outcomes$division),FUN=mean,na.rm=T)
kable(aggs[c(4,1,2,3,5),])
| Group.1 | error | error2 | aerror | |
|---|---|---|---|---|
| 4 | English FA Cup | 0.1138051 | 0.2680492 | 0.4982060 |
| 1 | Conference North | 0.3524609 | 0.1437739 | 0.3524609 |
| 2 | Conference South | 0.2623857 | 0.0688462 | 0.2623857 |
| 3 | English Championship | -0.0447275 | 0.1255953 | 0.2859019 |
| 5 | English League One | -0.0124267 | 0.2639907 | 0.4969437 |
The error column is the mean forecast error, the error2 column is the mean squared forecast error, and the aerror column is the absolute forecast error.
Finally, we list all the forecasts again with outcomes:
kable(forecast.outcomes[order(forecast.outcomes$date,forecast.outcomes$division),
c("date","division","team1","goals1","goals2","team2",
"outcome.forc","Ph","Pd","Pa","outcome.final","error","error2","aerror")],digits=3)
| date | division | team1 | goals1 | goals2 | team2 | outcome.forc | Ph | Pd | Pa | outcome.final | error | error2 | aerror | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 102 | 2015-02-14 | Conference North | Stockport | 2 | 0 | Hyde | 0.793 | 0.721 | 0.171 | 0.108 | 1.0 | 0.207 | 0.043 | 0.207 |
| 103 | 2015-02-14 | Conference North | Boston Utd | 5 | 0 | Bradford PA | 0.691 | 0.579 | 0.235 | 0.186 | 1.0 | 0.309 | 0.095 | 0.309 |
| 1 | 2015-02-14 | English Championship | Blackpool | 4 | 4 | Nottm Forest | 0.480 | 0.333 | 0.281 | 0.385 | 0.5 | 0.020 | 0.000 | 0.020 |
| 6 | 2015-02-14 | English Championship | Norwich | 2 | 0 | Wolves | 0.650 | 0.532 | 0.252 | 0.216 | 1.0 | 0.350 | 0.123 | 0.350 |
| 9 | 2015-02-14 | English Championship | Bolton | 3 | 4 | Watford | 0.494 | 0.346 | 0.282 | 0.372 | 0.0 | -0.494 | 0.244 | 0.494 |
| 12 | 2015-02-14 | English Championship | Sheff Wed | 0 | 0 | Brighton | 0.573 | 0.424 | 0.277 | 0.298 | 0.5 | -0.073 | 0.005 | 0.073 |
| 14 | 2015-02-14 | English Championship | Bournemouth | 1 | 1 | Huddersfield | 0.771 | 0.682 | 0.190 | 0.127 | 0.5 | -0.271 | 0.073 | 0.271 |
| 18 | 2015-02-14 | English Championship | Leeds | 1 | 0 | Millwall | 0.652 | 0.525 | 0.254 | 0.221 | 1.0 | 0.348 | 0.121 | 0.348 |
| 20 | 2015-02-14 | English Championship | Charlton | 3 | 0 | Brentford | 0.479 | 0.330 | 0.281 | 0.389 | 1.0 | 0.521 | 0.271 | 0.521 |
| 22 | 2015-02-14 | English Championship | Fulham | 1 | 2 | Ipswich | 0.473 | 0.324 | 0.281 | 0.395 | 0.0 | -0.473 | 0.223 | 0.473 |
| 123 | 2015-02-14 | English FA Cup | Blackburn | 4 | 1 | Stoke | 0.439 | 0.286 | 0.275 | 0.439 | 1.0 | 0.561 | 0.314 | 0.561 |
| 126 | 2015-02-14 | English FA Cup | C Palace | 1 | 2 | Liverpool | 0.493 | 0.341 | 0.282 | 0.377 | 0.0 | -0.493 | 0.243 | 0.493 |
| 128 | 2015-02-14 | English FA Cup | Derby | 1 | 2 | Reading | 0.746 | 0.648 | 0.206 | 0.145 | 0.0 | -0.746 | 0.556 | 0.746 |
| 133 | 2015-02-14 | English FA Cup | West Brom | 4 | 0 | West Ham | 0.498 | 0.347 | 0.282 | 0.370 | 1.0 | 0.502 | 0.252 | 0.502 |
| 27 | 2015-02-14 | English League One | Gillingham | 4 | 2 | MK Dons | 0.466 | 0.319 | 0.280 | 0.400 | 1.0 | 0.534 | 0.285 | 0.534 |
| 30 | 2015-02-14 | English League One | Peterborough | 2 | 1 | Rochdale | 0.505 | 0.353 | 0.282 | 0.365 | 1.0 | 0.495 | 0.245 | 0.495 |
| 32 | 2015-02-14 | English League One | Chesterfield | 2 | 3 | Leyton Orient | 0.702 | 0.585 | 0.233 | 0.182 | 0.0 | -0.702 | 0.493 | 0.702 |
| 33 | 2015-02-14 | English League One | Doncaster | 3 | 0 | Yeovil | 0.690 | 0.570 | 0.239 | 0.191 | 1.0 | 0.310 | 0.096 | 0.310 |
| 36 | 2015-02-14 | English League One | Scunthorpe | 3 | 1 | Swindon | 0.487 | 0.339 | 0.282 | 0.379 | 1.0 | 0.513 | 0.264 | 0.513 |
| 37 | 2015-02-14 | English League One | Walsall | 0 | 1 | Port Vale | 0.664 | 0.539 | 0.250 | 0.212 | 0.0 | -0.664 | 0.441 | 0.664 |
| 39 | 2015-02-14 | English League One | Bristol C | 1 | 3 | Sheff Utd | 0.671 | 0.554 | 0.245 | 0.201 | 0.0 | -0.671 | 0.450 | 0.671 |
| 42 | 2015-02-14 | English League One | Crewe | 2 | 0 | Fleetwood | 0.553 | 0.405 | 0.280 | 0.315 | 1.0 | 0.447 | 0.200 | 0.447 |
| 43 | 2015-02-14 | English League One | Oldham | 0 | 1 | Colchester | 0.687 | 0.569 | 0.239 | 0.192 | 0.0 | -0.687 | 0.472 | 0.687 |
| 45 | 2015-02-14 | English League One | Crawley | 5 | 1 | Barnsley | 0.474 | 0.322 | 0.281 | 0.398 | 1.0 | 0.526 | 0.276 | 0.526 |
| 49 | 2015-02-14 | English League Two | Burton | 2 | 0 | Oxford | 0.681 | 0.557 | 0.244 | 0.199 | 1.0 | 0.319 | 0.102 | 0.319 |
| 52 | 2015-02-14 | English League Two | Hartlepool | 1 | 3 | Stevenage | 0.492 | 0.343 | 0.282 | 0.375 | 0.0 | -0.492 | 0.242 | 0.492 |
| 55 | 2015-02-14 | English League Two | Luton | 1 | 0 | Carlisle | 0.711 | 0.598 | 0.228 | 0.174 | 1.0 | 0.289 | 0.083 | 0.289 |
| 57 | 2015-02-14 | English League Two | Mansfield | 1 | 1 | Northampton | 0.502 | 0.351 | 0.282 | 0.367 | 0.5 | -0.002 | 0.000 | 0.002 |
| 60 | 2015-02-14 | English League Two | Cheltenham | 1 | 2 | Bury | 0.479 | 0.329 | 0.281 | 0.390 | 0.0 | -0.479 | 0.229 | 0.479 |
| 61 | 2015-02-14 | English League Two | York | 2 | 0 | Tranmere | 0.562 | 0.416 | 0.279 | 0.305 | 1.0 | 0.438 | 0.192 | 0.438 |
| 64 | 2015-02-14 | English League Two | Wycombe | 1 | 2 | Newport Co | 0.648 | 0.522 | 0.255 | 0.223 | 0.0 | -0.648 | 0.420 | 0.648 |
| 65 | 2015-02-14 | English League Two | Shrewsbury | 2 | 0 | AFC W’bledon | 0.678 | 0.558 | 0.243 | 0.199 | 1.0 | 0.322 | 0.104 | 0.322 |
| 68 | 2015-02-14 | English League Two | Portsmouth | 1 | 0 | Exeter | 0.589 | 0.449 | 0.273 | 0.278 | 1.0 | 0.411 | 0.169 | 0.411 |
| 69 | 2015-02-14 | English League Two | Southend | 1 | 2 | Accrington | 0.694 | 0.578 | 0.236 | 0.186 | 0.0 | -0.694 | 0.481 | 0.694 |
| 71 | 2015-02-14 | English League Two | Plymouth | 2 | 0 | Cambridge U | 0.582 | 0.437 | 0.275 | 0.287 | 1.0 | 0.418 | 0.175 | 0.418 |
| 73 | 2015-02-14 | Football Conference | Altrincham | 2 | 2 | Forest Green | 0.533 | 0.385 | 0.281 | 0.333 | 0.5 | -0.033 | 0.001 | 0.033 |
| 76 | 2015-02-14 | Football Conference | Aldershot | 2 | 1 | Welling | 0.580 | 0.439 | 0.275 | 0.286 | 1.0 | 0.420 | 0.176 | 0.420 |
| 77 | 2015-02-14 | Football Conference | Kidderminster | 1 | 1 | Woking | 0.548 | 0.398 | 0.280 | 0.321 | 0.5 | -0.048 | 0.002 | 0.048 |
| 79 | 2015-02-14 | Football Conference | Halifax | 3 | 2 | Dover | 0.554 | 0.406 | 0.280 | 0.314 | 1.0 | 0.446 | 0.199 | 0.446 |
| 82 | 2015-02-14 | Football Conference | Southport | 1 | 1 | Macclesfield | 0.411 | 0.267 | 0.271 | 0.463 | 0.5 | 0.089 | 0.008 | 0.089 |
| 83 | 2015-02-14 | Football Conference | Eastleigh | 1 | 2 | Torquay | 0.623 | 0.491 | 0.264 | 0.245 | 0.0 | -0.623 | 0.388 | 0.623 |
| 86 | 2015-02-14 | Football Conference | Gateshead | 1 | 2 | Nuneaton | 0.782 | 0.690 | 0.187 | 0.124 | 0.0 | -0.782 | 0.611 | 0.782 |
| 87 | 2015-02-14 | Football Conference | Braintree | 2 | 1 | Alfreton | 0.681 | 0.570 | 0.239 | 0.191 | 1.0 | 0.319 | 0.102 | 0.319 |
| 89 | 2015-02-14 | Football Conference | Wrexham | 1 | 0 | Barnet | 0.432 | 0.286 | 0.275 | 0.439 | 1.0 | 0.568 | 0.323 | 0.568 |
| 92 | 2015-02-14 | Football Conference | Grimsby | 0 | 1 | Bristol R | 0.604 | 0.467 | 0.270 | 0.263 | 0.0 | -0.604 | 0.365 | 0.604 |
| 94 | 2015-02-14 | Football Conference | Lincoln | 0 | 1 | Chester | 0.621 | 0.490 | 0.264 | 0.246 | 0.0 | -0.621 | 0.386 | 0.621 |
| 96 | 2015-02-14 | Football Conference | Telford | 2 | 3 | Dartford | 0.622 | 0.495 | 0.263 | 0.242 | 0.0 | -0.622 | 0.387 | 0.622 |
| 105 | 2015-02-14 | Ryman Premier | Canvey Isl. | 1 | 1 | Grays | 0.659 | 0.553 | 0.245 | 0.202 | 0.5 | -0.159 | 0.025 | 0.159 |
| 119 | 2015-02-15 | English FA Cup | Arsenal | 2 | 0 | Middlesbro | 0.695 | 0.583 | 0.234 | 0.183 | 1.0 | 0.305 | 0.093 | 0.305 |
| 120 | 2015-02-15 | English FA Cup | Aston Villa | 2 | 1 | Leicester | 0.540 | 0.389 | 0.281 | 0.329 | 1.0 | 0.460 | 0.211 | 0.460 |
| 124 | 2015-02-15 | English FA Cup | Bradford | 2 | 0 | Sunderland | 0.379 | 0.240 | 0.262 | 0.498 | 1.0 | 0.621 | 0.385 | 0.621 |
| 53 | 2015-02-15 | English League Two | Morecambe | 2 | 3 | Dag & Red | 0.598 | 0.458 | 0.272 | 0.271 | 0.0 | -0.598 | 0.358 | 0.598 |
| 130 | 2015-02-16 | English FA Cup | Preston | 1 | 3 | Man Utd | 0.299 | 0.174 | 0.228 | 0.598 | 0.0 | -0.299 | 0.089 | 0.299 |
| 97 | 2015-02-17 | Conference South | Bath City | 7 | 4 | Farnborough | 0.738 | 0.627 | 0.216 | 0.157 | 1.0 | 0.262 | 0.069 | 0.262 |
| 7 | 2015-02-17 | English Championship | Rotherham | 3 | 3 | Derby | 0.405 | 0.260 | 0.269 | 0.471 | 0.5 | 0.095 | 0.009 | 0.095 |
| 16 | 2015-02-17 | English Championship | Reading | 0 | 1 | Wigan | 0.650 | 0.518 | 0.256 | 0.225 | 0.0 | -0.650 | 0.423 | 0.650 |
| 24 | 2015-02-17 | English Championship | Cardiff | 1 | 1 | Blackburn | 0.523 | 0.374 | 0.282 | 0.344 | 0.5 | -0.023 | 0.001 | 0.023 |
| 25 | 2015-02-17 | English League One | Doncaster | 2 | 1 | Crewe | 0.647 | 0.525 | 0.254 | 0.221 | 1.0 | 0.353 | 0.125 | 0.353 |
| 48 | 2015-02-17 | English League One | Scunthorpe | 2 | 0 | Chesterfield | 0.555 | 0.412 | 0.279 | 0.309 | 1.0 | 0.445 | 0.198 | 0.445 |
| 113 | 2015-02-17 | English League One | Notts Co | 1 | 2 | Sheff Utd | 0.492 | 0.339 | 0.282 | 0.380 | 0.0 | -0.492 | 0.242 | 0.492 |
| 114 | 2015-02-17 | English League One | Bristol C | 2 | 0 | Peterborough | 0.747 | 0.641 | 0.210 | 0.149 | 1.0 | 0.253 | 0.064 | 0.253 |
| 117 | 2015-02-17 | English League One | Colchester | 0 | 1 | MK Dons | 0.383 | 0.245 | 0.264 | 0.491 | 0.0 | -0.383 | 0.146 | 0.383 |
| 111 | 2015-02-17 | English League Two | Mansfield | 1 | 0 | Luton | 0.449 | 0.298 | 0.277 | 0.425 | 1.0 | 0.551 | 0.303 | 0.551 |
| 99 | 2015-02-18 | Conference North | Bradford PA | 2 | 0 | Stockport | 0.459 | 0.310 | 0.279 | 0.411 | 1.0 | 0.541 | 0.293 | 0.541 |
| 4 | 2015-02-18 | English Championship | Birmingham | 1 | 1 | Middlesbro | 0.387 | 0.242 | 0.263 | 0.495 | 0.5 | 0.113 | 0.013 | 0.113 |
| 109 | 2015-02-18 | English League One | Leyton Orient | 0 | 2 | Bradford | 0.477 | 0.329 | 0.281 | 0.390 | 0.0 | -0.477 | 0.227 | 0.477 |