This is a very simple R code to see the Points Per Game achieved by each team in the English Football League over the past 10 years, inspired by a tweet I saw about AFC Wimbledon’s record. First, we need to load the data, which we do from football-data.co.uk.
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
co.we <- c("E0", "E1", "E2", "E3") #Website country codes (football-data)
seasons <- c("1112", "1213", "1314", "1415", "1516", "1617", "1718", "1819", "1920", "2021")
matchdataTemp <- NULL; matchdata <- NULL
for (i in seasons){
for (j in 1:4){
matchdataTemp <- read.csv(paste0('https://www.football-data.co.uk/mmz4281/', i, '/', co.we[j],'.csv'), fileEncoding = 'latin1')
matchdataTemp <- matchdataTemp[ ,c("Div", "Date", "HomeTeam", "AwayTeam", "FTHG", "FTAG", "FTR")]
matchdata <- rbind(matchdata, matchdataTemp)
}
}
Next, we need to find the point data, which we do by first using the Unique tool from the dplyr package to find all unique team names and creating a new dataframe with these. For each row in the PointData dataframe, we compare against each row in the MatchData dataframe: this code checks if the Home Team or Away Team is the team of interest, and if so, allocates points (3 for a win, 1 for a draw). In addition, we find the total number of wins, draws, and losses for each side.
pointdata <- NULL
for (i in unique(matchdata$HomeTeam)){
pointdata <- rbind(pointdata, i)
}
pointdata <- data.frame(pointdata)
pointdata$games <- with(pointdata, 0)
pointdata$W <- with(pointdata, 0)
pointdata$D <- with(pointdata, 0)
pointdata$L <- with(pointdata, 0)
pointdata$points <- with(pointdata, 0)
colnames(pointdata) <- c("team", "games", "W", "D", "L", "points")
rownames(pointdata) <- 1:nrow(pointdata)
for (i in 1:nrow(pointdata)){
for (j in 1:nrow(matchdata)){
if (matchdata$HomeTeam[j] == pointdata$team[i]){
if (matchdata$FTR[j] == "H"){
pointdata$points[i] <- pointdata$points[i] + 3
pointdata$W[i] <- pointdata$W[i] + 1}
else if (matchdata$FTR[j] == "D"){
pointdata$points[i] <- pointdata$points[i] + 1
pointdata$D[i] <- pointdata$D[i] + 1}
else{pointdata$L[i] <- pointdata$L[i] + 1}
pointdata$games[i] <- pointdata$games[i] + 1}
else if (matchdata$AwayTeam[j] == pointdata$team[i]){
if (matchdata$FTR[j] == "A"){
pointdata$points[i] <- pointdata$points[i] + 3
pointdata$W[i] <- pointdata$W[i] + 1}
else if (matchdata$FTR[j] == "D"){
pointdata$points[i] <- pointdata$points[i] + 1
pointdata$D[i] <- pointdata$D[i] + 1}
else{pointdata$L[i] <- pointdata$L[i] + 1}
pointdata$games[i] <- pointdata$games[i] + 1
}
}
}
Similarly, to find each side’s goal difference, we use a similar method to locate the matches each team is involved in.
pointdata$gFor <- with(pointdata, 0)
pointdata$gAgainst <- with(pointdata, 0)
for (i in 1:nrow(pointdata)){
for (j in 1:nrow(matchdata)){
if (matchdata$HomeTeam[j] == pointdata$team[i]){
pointdata$gFor[i] <- pointdata$gFor[i] + matchdata$FTHG[j]
pointdata$gAgainst[i] <- pointdata$gAgainst[i] + matchdata$FTAG[j]}
else if (matchdata$AwayTeam[j] == pointdata$team[i]){
pointdata$gFor[i] <- pointdata$gFor[i] + matchdata$FTAG[j]
pointdata$gAgainst[i] <- pointdata$gAgainst[i] + matchdata$FTHG[j]
}
}
}
pointdata$gDiff <- with(pointdata, gFor - gAgainst)
Finally, we find each teams Points Per Game, and re-number the table to reflect an actual league table.
pointdata$ppg <- with(pointdata, 0)
for (i in 1:nrow(pointdata)){
pointdata$ppg[i] <- round(pointdata$points[i] / pointdata$games[i],3)
}
#Order, highest to lowest PPG
pointdata <- pointdata[order(-pointdata$ppg),]
#Positions
rownames(pointdata) <- 1:nrow(pointdata)
pointdata[1:104,]
## team games W D L points gFor gAgainst gDiff ppg
## 1 Man City 377 259 58 60 835 870 329 541 2.215
## 2 Man United 378 214 88 76 730 673 380 293 1.931
## 3 Liverpool 377 212 90 75 726 731 407 324 1.926
## 4 Chelsea 378 213 84 81 723 677 394 283 1.913
## 5 Tottenham 377 204 81 92 693 663 415 248 1.838
## 6 Arsenal 378 201 84 93 687 680 431 249 1.817
## 7 Brentford 460 210 118 132 748 716 524 192 1.626
## 8 Lincoln 173 77 48 48 279 250 187 63 1.613
## 9 Sheffield United 441 196 110 135 698 615 495 120 1.583
## 10 Luton 322 141 83 98 506 466 370 96 1.571
## 11 Leicester 402 179 92 131 629 621 493 128 1.565
## 12 Derby 460 187 128 145 689 641 545 96 1.498
## 13 Wolves 425 175 108 142 633 576 526 50 1.489
## 14 Oxford 449 180 121 148 661 628 524 104 1.472
## 15 Everton 377 149 107 121 554 523 470 53 1.469
## 16 Portsmouth 449 181 116 152 659 620 526 94 1.468
## 17 Swindon 450 188 95 167 659 637 573 64 1.464
## 18 Middlesbrough 452 181 118 153 661 552 492 60 1.462
## 19 Cardiff 444 175 124 145 649 580 560 20 1.462
## 20 Preston 460 177 141 142 672 600 534 66 1.461
## 21 Leeds 449 186 97 166 655 604 569 35 1.459
## 22 Salford 83 32 25 26 121 103 80 23 1.458
## 23 Peterboro 449 185 93 171 648 692 609 83 1.443
## 24 Charlton 460 175 133 152 658 593 561 32 1.430
## 25 Exeter 451 176 117 158 645 610 576 34 1.430
## 26 Burton 449 175 117 157 642 562 588 -26 1.430
## 27 Fleetwood Town 403 153 111 139 570 503 464 39 1.414
## 28 Plymouth 451 175 111 165 636 570 564 6 1.410
## 29 Watford 420 164 99 157 591 581 571 10 1.407
## 30 Brighton 425 152 140 133 596 510 480 30 1.402
## 31 Accrington 449 169 122 158 629 587 605 -18 1.401
## 32 Sheffield Weds 460 171 130 159 643 583 562 21 1.398
## 33 Forest Green 174 66 45 63 243 224 215 9 1.397
## 34 Milton Keynes Dons 449 172 111 166 627 623 555 68 1.396
## 35 Norwich 420 160 106 154 586 576 598 -22 1.395
## 36 Bournemouth 420 161 102 157 585 603 592 11 1.393
## 37 Burnley 409 153 110 146 569 491 502 -11 1.391
## 38 Bradford 451 163 130 158 619 544 540 4 1.373
## 39 Gillingham 449 164 124 161 616 616 602 14 1.372
## 40 Cheltenham 404 146 114 144 552 503 507 -4 1.366
## 41 Wycombe 448 165 114 169 609 549 580 -31 1.359
## 42 Shrewsbury 448 161 126 161 609 527 535 -8 1.359
## 43 Southend 449 165 113 171 608 557 570 -13 1.354
## 44 Southampton 385 140 101 144 521 519 517 2 1.353
## 45 Doncaster 448 163 114 171 603 577 585 -8 1.346
## 46 Mansfield 358 122 116 120 482 443 426 17 1.346
## 47 Blackburn 452 158 134 160 608 615 598 17 1.345
## 48 Cambridge 313 115 76 122 421 394 394 0 1.345
## 49 West Ham 385 139 100 146 517 526 544 -18 1.343
## 50 Ipswich 450 159 126 165 603 535 574 -39 1.340
## 51 Hull 436 161 98 177 581 558 578 -20 1.333
## 52 Scunthorpe 451 156 133 162 601 577 605 -28 1.333
## 53 Carlisle 451 157 129 165 600 584 646 -62 1.330
## 54 Northampton 451 161 115 175 598 573 619 -46 1.326
## 55 Coventry 448 156 123 169 591 549 570 -21 1.319
## 56 Bristol City 460 161 121 178 604 615 638 -23 1.313
## 57 Reading 452 158 118 176 592 568 610 -42 1.310
## 58 Millwall 460 155 137 168 602 541 587 -46 1.309
## 59 Newport County 358 122 102 134 468 405 448 -43 1.307
## 60 Port Vale 451 158 115 178 589 565 601 -36 1.306
## 61 Swansea 404 141 104 159 527 489 537 -48 1.304
## 62 Wigan 444 154 115 175 577 562 575 -13 1.300
## 63 Torquay 138 48 35 55 179 160 178 -18 1.297
## 64 Leyton Orient 358 127 83 148 464 454 495 -41 1.296
## 65 Crewe 451 160 104 187 584 567 664 -97 1.295
## 66 Barnsley 460 160 115 185 595 580 633 -53 1.293
## 67 Newcastle 385 138 83 164 497 472 557 -85 1.291
## 68 Rotherham 449 156 108 185 576 596 650 -54 1.283
## 69 Crawley Town 451 152 122 177 578 550 637 -87 1.282
## 70 Walsall 450 142 150 158 576 524 564 -40 1.280
## 71 Nott'm Forest 460 151 135 174 588 561 588 -27 1.278
## 72 Fulham 417 142 106 169 532 553 637 -84 1.276
## 73 Bristol Rvs 403 138 100 165 514 493 544 -51 1.275
## 74 Rochdale 448 152 113 183 569 598 667 -69 1.270
## 75 Blackpool 449 143 140 166 569 538 575 -37 1.267
## 76 Bury 368 122 100 146 466 464 516 -52 1.266
## 77 Notts County 368 124 91 153 463 472 543 -71 1.258
## 78 Colchester 451 144 133 174 565 557 631 -74 1.253
## 79 Stevenage 450 146 125 179 563 527 575 -48 1.251
## 80 Tranmere 310 102 81 127 387 358 407 -49 1.248
## 81 Aldershot 92 30 24 38 114 96 112 -16 1.239
## 82 Harrogate 46 16 9 21 57 52 61 -9 1.239
## 83 Birmingham 460 143 140 177 569 544 633 -89 1.237
## 84 West Brom 393 123 115 155 484 483 549 -66 1.232
## 85 Crystal Palace 393 128 97 168 481 452 543 -91 1.224
## 86 Stoke 404 122 124 158 490 437 546 -109 1.213
## 87 Chesterfield 322 104 78 140 390 403 452 -49 1.211
## 88 AFC Wimbledon 449 137 131 181 542 517 619 -102 1.207
## 89 Huddersfield 444 138 118 188 532 515 663 -148 1.198
## 90 Sunderland 402 117 130 155 481 485 545 -60 1.197
## 91 Morecambe 451 138 125 188 539 544 642 -98 1.195
## 92 Aston Villa 401 123 108 170 477 472 575 -103 1.190
## 93 QPR 436 138 104 194 518 516 635 -119 1.188
## 94 Oldham 451 131 139 181 532 516 626 -110 1.180
## 95 Grimsby 221 68 55 98 259 228 305 -77 1.172
## 96 Bolton 440 131 117 192 510 491 650 -159 1.159
## 97 York 184 48 68 68 212 199 239 -40 1.152
## 98 Barnet 230 68 58 104 262 269 335 -66 1.139
## 99 Dag and Red 230 67 53 110 254 262 333 -71 1.104
## 100 Barrow 46 13 11 22 50 53 59 -6 1.087
## 101 Yeovil 368 98 100 170 394 402 550 -148 1.071
## 102 Hartlepool 276 75 67 134 292 281 395 -114 1.058
## 103 Hereford 46 10 14 22 44 50 70 -20 0.957
## 104 Macclesfield 129 25 42 62 117 119 185 -66 0.907