Welcome

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.

Loading the Data

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)
  }
}

Point and Match Data

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
    }
  }
}

Goal Difference

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)

Final Table

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