gr-analytics 0.3.1__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/PKG-INFO +26 -1
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/README.md +25 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics/__init__.py +79 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics/data/driver_data.csv +232 -166
- gr_analytics-0.3.2/gr_analytics/data/race_results.csv +89 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics.egg-info/PKG-INFO +26 -1
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics.egg-info/SOURCES.txt +2 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/pyproject.toml +1 -1
- gr_analytics-0.3.2/tests/test_eight_race_average.py +131 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics.egg-info/dependency_links.txt +0 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics.egg-info/requires.txt +0 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/gr_analytics.egg-info/top_level.txt +0 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/setup.cfg +0 -0
- {gr_analytics-0.3.1 → gr_analytics-0.3.2}/tests/test_scoring.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gr_analytics
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Scoring and salary calculation for GridRival fantasy F1
|
|
5
5
|
Author: nce8
|
|
6
6
|
License-Expression: MIT
|
|
@@ -135,6 +135,31 @@ Bundled driver data (`gr_analytics/data/driver_data.csv`) contains starting sala
|
|
|
135
135
|
- `round=0` — pre-season (before Australia 2026)
|
|
136
136
|
- `round=1` — post-Australia 2026
|
|
137
137
|
|
|
138
|
+
## Eight-Race Average
|
|
139
|
+
|
|
140
|
+
GridRival's "8 race average" can be computed instead of entered by hand.
|
|
141
|
+
GridRival seeds the season with 8 slots holding a hard-coded initial
|
|
142
|
+
average (the `round=0` values in driver_data); each race replaces one
|
|
143
|
+
slot with the driver's classified finishing position, and the displayed
|
|
144
|
+
value is the **ceiling** of the slot mean. Race finishing positions live
|
|
145
|
+
in `gr_analytics/data/race_results.csv`.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from gr_analytics import calculate_eight_race_averages, eight_race_average
|
|
149
|
+
|
|
150
|
+
# All drivers, after the latest round in race_results.csv
|
|
151
|
+
calculate_eight_race_averages()
|
|
152
|
+
|
|
153
|
+
# All drivers, after round 2
|
|
154
|
+
calculate_eight_race_averages(through_round=2)
|
|
155
|
+
|
|
156
|
+
# Single driver from scratch: seed 1, finished P6 then P16
|
|
157
|
+
eight_race_average(1, [6, 16])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This reproduces GridRival's displayed values exactly for all rounds so
|
|
161
|
+
far (verified in `tests/test_eight_race_average.py`).
|
|
162
|
+
|
|
138
163
|
## Lineup Optimisation
|
|
139
164
|
|
|
140
165
|
`optimal_lineup` uses mixed-integer linear programming (via `scipy.optimize.milp`) to find the best 5-driver + 1-constructor lineup within a salary budget.
|
|
@@ -118,6 +118,31 @@ Bundled driver data (`gr_analytics/data/driver_data.csv`) contains starting sala
|
|
|
118
118
|
- `round=0` — pre-season (before Australia 2026)
|
|
119
119
|
- `round=1` — post-Australia 2026
|
|
120
120
|
|
|
121
|
+
## Eight-Race Average
|
|
122
|
+
|
|
123
|
+
GridRival's "8 race average" can be computed instead of entered by hand.
|
|
124
|
+
GridRival seeds the season with 8 slots holding a hard-coded initial
|
|
125
|
+
average (the `round=0` values in driver_data); each race replaces one
|
|
126
|
+
slot with the driver's classified finishing position, and the displayed
|
|
127
|
+
value is the **ceiling** of the slot mean. Race finishing positions live
|
|
128
|
+
in `gr_analytics/data/race_results.csv`.
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from gr_analytics import calculate_eight_race_averages, eight_race_average
|
|
132
|
+
|
|
133
|
+
# All drivers, after the latest round in race_results.csv
|
|
134
|
+
calculate_eight_race_averages()
|
|
135
|
+
|
|
136
|
+
# All drivers, after round 2
|
|
137
|
+
calculate_eight_race_averages(through_round=2)
|
|
138
|
+
|
|
139
|
+
# Single driver from scratch: seed 1, finished P6 then P16
|
|
140
|
+
eight_race_average(1, [6, 16])
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
This reproduces GridRival's displayed values exactly for all rounds so
|
|
144
|
+
far (verified in `tests/test_eight_race_average.py`).
|
|
145
|
+
|
|
121
146
|
## Lineup Optimisation
|
|
122
147
|
|
|
123
148
|
`optimal_lineup` uses mixed-integer linear programming (via `scipy.optimize.milp`) to find the best 5-driver + 1-constructor lineup within a salary budget.
|
|
@@ -34,6 +34,16 @@ def driver_data() -> pd.DataFrame:
|
|
|
34
34
|
return pd.read_csv(_DATA_DIR / "driver_data.csv")
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def race_results() -> pd.DataFrame:
|
|
38
|
+
"""
|
|
39
|
+
Load and return race_results.csv as a DataFrame.
|
|
40
|
+
|
|
41
|
+
One row per driver per round with the official classified finishing
|
|
42
|
+
position (DNF/DNS drivers receive their classified position).
|
|
43
|
+
"""
|
|
44
|
+
return pd.read_csv(_DATA_DIR / "race_results.csv")
|
|
45
|
+
|
|
46
|
+
|
|
37
47
|
# ---------------------------------------------------------------------------
|
|
38
48
|
# Lookup tables — Drivers
|
|
39
49
|
# ---------------------------------------------------------------------------
|
|
@@ -330,6 +340,75 @@ def _score_constructors(
|
|
|
330
340
|
# ---------------------------------------------------------------------------
|
|
331
341
|
|
|
332
342
|
|
|
343
|
+
def eight_race_average(initial_average: float, finishing_positions: list) -> int:
|
|
344
|
+
"""
|
|
345
|
+
GridRival's eight-race average after a sequence of races.
|
|
346
|
+
|
|
347
|
+
GridRival seeds each driver's season with 8 "slots" holding a
|
|
348
|
+
hard-coded initial average. Each race replaces one slot with the
|
|
349
|
+
driver's official classified finishing position, so after 8 races the
|
|
350
|
+
initial average has fully rolled off and the value is a true rolling
|
|
351
|
+
average of the last 8 finishes. The displayed value is the ceiling of
|
|
352
|
+
the slot mean (verified against GridRival's displayed values for
|
|
353
|
+
rounds 1-4 of 2026).
|
|
354
|
+
|
|
355
|
+
Parameters
|
|
356
|
+
----------
|
|
357
|
+
initial_average : float
|
|
358
|
+
The hard-coded season-start average (round 0 of driver_data).
|
|
359
|
+
finishing_positions : list of int
|
|
360
|
+
Classified finishing positions in every race so far, oldest first.
|
|
361
|
+
|
|
362
|
+
Returns
|
|
363
|
+
-------
|
|
364
|
+
int
|
|
365
|
+
The eight-race average as GridRival displays it.
|
|
366
|
+
"""
|
|
367
|
+
slots = [initial_average] * 8 + [int(p) for p in finishing_positions]
|
|
368
|
+
return math.ceil(sum(slots[-8:]) / 8)
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def calculate_eight_race_averages(through_round: int = None) -> pd.Series:
|
|
372
|
+
"""
|
|
373
|
+
Compute every driver's eight-race average after ``through_round``.
|
|
374
|
+
|
|
375
|
+
Uses the round-0 seeds in driver_data.csv and the finishing positions
|
|
376
|
+
in race_results.csv. Matches the convention of driver_data, where the
|
|
377
|
+
round-N row holds the state *after* race N (so the returned values are
|
|
378
|
+
what GridRival displays going into race N+1).
|
|
379
|
+
|
|
380
|
+
Parameters
|
|
381
|
+
----------
|
|
382
|
+
through_round : int, optional
|
|
383
|
+
Include races 1 through this round. Defaults to the latest round
|
|
384
|
+
in race_results. Pass 0 to get the season-start seeds.
|
|
385
|
+
|
|
386
|
+
Returns
|
|
387
|
+
-------
|
|
388
|
+
Series
|
|
389
|
+
Eight-race average indexed by driver_abbr.
|
|
390
|
+
"""
|
|
391
|
+
dd = driver_data()
|
|
392
|
+
seeds = (
|
|
393
|
+
dd[(dd["type"] == "driver") & (dd["round"] == 0)]
|
|
394
|
+
.set_index("driver_abbr")["eight_race_average"]
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
results = race_results()
|
|
398
|
+
if through_round is None:
|
|
399
|
+
through_round = results["round"].max()
|
|
400
|
+
results = results[results["round"] <= through_round].sort_values("round")
|
|
401
|
+
|
|
402
|
+
averages = {
|
|
403
|
+
abbr: eight_race_average(
|
|
404
|
+
seed,
|
|
405
|
+
results.loc[results["driver_abbr"] == abbr, "finishing_position"],
|
|
406
|
+
)
|
|
407
|
+
for abbr, seed in seeds.items()
|
|
408
|
+
}
|
|
409
|
+
return pd.Series(averages, name="eight_race_average").rename_axis("driver_abbr")
|
|
410
|
+
|
|
411
|
+
|
|
333
412
|
def _validate_scenario(scenario: pd.DataFrame) -> None:
|
|
334
413
|
"""Check that qualifying and race positions are sequential and unique."""
|
|
335
414
|
errors = []
|
|
@@ -1,166 +1,232 @@
|
|
|
1
|
-
type,driver_abbr,driver_name,driver_team,round,starting_salary,eight_race_average,points_from_last_race
|
|
2
|
-
driver,VER,M. Verstappen,RBR,0,30,1,
|
|
3
|
-
driver,RUS,G. Russell,MER,0,28.7,2,
|
|
4
|
-
driver,NOR,L. Norris,MCL,0,27.4,3,
|
|
5
|
-
driver,PIA,O. Piastri,MCL,0,26.1,4,
|
|
6
|
-
driver,ANT,K. Antonelli,MER,0,24.8,5,
|
|
7
|
-
driver,LEC,C. Leclerc,FER,0,23.5,6,
|
|
8
|
-
driver,ALO,F. Alonso,AMR,0,22.2,7,
|
|
9
|
-
driver,HAM,L. Hamilton,FER,0,20.9,8,
|
|
10
|
-
driver,HAD,I. Hadjar,RBR,0,19.6,9,
|
|
11
|
-
driver,GAS,P. Gasly,ALP,0,18.3,10,
|
|
12
|
-
driver,STR,L. Stroll,AMR,0,17,11,
|
|
13
|
-
driver,SAI,C. Sainz Jr,WIL,0,15.7,12,
|
|
14
|
-
driver,LAW,L. Lawson,RBS,0,14.4,13,
|
|
15
|
-
driver,ALB,A. Albon,WIL,0,13.1,14,
|
|
16
|
-
driver,HUL,N. Hulkenberg,AUD,0,11.8,15,
|
|
17
|
-
driver,BOR,G. Bortoleto,AUD,0,10.5,16,
|
|
18
|
-
driver,BEA,O. Bearman,HAS,0,9.2,17,
|
|
19
|
-
driver,OCO,E. Ocon,HAS,0,7.9,18,
|
|
20
|
-
driver,BOT,V. Bottas,CAD,0,4.7,19,
|
|
21
|
-
driver,PER,S. Perez,CAD,0,4.7,19,
|
|
22
|
-
driver,COL,F. Colapinto,ALP,0,4.7,19,
|
|
23
|
-
driver,LIN,A. Lindblad,RBS,0,4.6,
|
|
24
|
-
team,MER,MER,,0,28.5,1,
|
|
25
|
-
team,MCL,MCL,,0,28.5,2,
|
|
26
|
-
team,RBR,RBR,,0,25,3,
|
|
27
|
-
team,FER,FER,,0,22.5,4,
|
|
28
|
-
team,AMR,AMR,,0,20,5,
|
|
29
|
-
team,WIL,WIL,,0,17.5,6,
|
|
30
|
-
team,RBS,RBS,,0,15,7,
|
|
31
|
-
team,ALP,ALP,,0,12.5,8,
|
|
32
|
-
team,AUD,AUD,,0,10,9,
|
|
33
|
-
team,CAD,CAD,,0,7.5,10,
|
|
34
|
-
team,HAS,HAS,,0,5,11,
|
|
35
|
-
driver,VER,M. Verstappen,RBR,1,28.2,2,
|
|
36
|
-
driver,RUS,G. Russell,MER,1,29.6,2,
|
|
37
|
-
driver,NOR,L. Norris,MCL,1,26.7,4,
|
|
38
|
-
driver,PIA,O. Piastri,MCL,1,24.1,7,
|
|
39
|
-
driver,ANT,K. Antonelli,MER,1,25.9,5,
|
|
40
|
-
driver,LEC,C. Leclerc,FER,1,24.5,6,
|
|
41
|
-
driver,ALO,F. Alonso,AMR,1,20.2,9,
|
|
42
|
-
driver,HAM,L. Hamilton,FER,1,22.1,8,
|
|
43
|
-
driver,HAD,I. Hadjar,RBR,1,17.6,11,
|
|
44
|
-
driver,GAS,P. Gasly,ALP,1,18.3,10,
|
|
45
|
-
driver,STR,L. Stroll,AMR,1,15,12,
|
|
46
|
-
driver,SAI,C. Sainz Jr,WIL,1,13.9,13,
|
|
47
|
-
driver,LAW,L. Lawson,RBS,1,14.5,13,
|
|
48
|
-
driver,ALB,A. Albon,WIL,1,13.9,14,
|
|
49
|
-
driver,HUL,N. Hulkenberg,AUD,1,9.8,16,
|
|
50
|
-
driver,BOR,G. Bortoleto,AUD,1,12.5,
|
|
51
|
-
driver,BEA,O. Bearman,HAS,1,11.2,16,
|
|
52
|
-
driver,OCO,E. Ocon,HAS,1,9.9,18,
|
|
53
|
-
driver,BOT,V. Bottas,CAD,1,4.5,19,
|
|
54
|
-
driver,PER,S. Perez,CAD,1,6.4,19,
|
|
55
|
-
driver,COL,F. Colapinto,ALP,1,6.7,19,
|
|
56
|
-
driver,LIN,A. Lindblad,RBS,1,6.6,18,
|
|
57
|
-
team,MER,MER,,1,28.8,,
|
|
58
|
-
team,MCL,MCL,,1,25.7,,
|
|
59
|
-
team,RBR,RBR,,1,22.4,,
|
|
60
|
-
team,FER,FER,,1,23.7,,
|
|
61
|
-
team,AMR,AMR,,1,17,,
|
|
62
|
-
team,WIL,WIL,,1,16.1,,
|
|
63
|
-
team,RBS,RBS,,1,17.4,,
|
|
64
|
-
team,ALP,ALP,,1,14.2,,
|
|
65
|
-
team,AUD,AUD,,1,9.8,,
|
|
66
|
-
team,CAD,CAD,,1,7.3,,
|
|
67
|
-
team,HAS,HAS,,1,8,,
|
|
68
|
-
driver,RUS,G. Russell,MER,2,29.5,2,171
|
|
69
|
-
driver,ANT,K. Antonelli,MER,2,27.5,5,174
|
|
70
|
-
driver,VER,M. Verstappen,RBR,2,26.2,4,132
|
|
71
|
-
driver,LEC,C. Leclerc,FER,2,24.8,6,164
|
|
72
|
-
driver,NOR,L. Norris,MCL,2,24.7,6,107
|
|
73
|
-
driver,HAM,L. Hamilton,FER,2,24.1,7,169
|
|
74
|
-
driver,PIA,O. Piastri,MCL,2,22.1,8,50
|
|
75
|
-
driver,GAS,P. Gasly,ALP,2,19.8,10,143
|
|
76
|
-
driver,ALO,F. Alonso,AMR,2,18.2,10,78
|
|
77
|
-
driver,HAD,I. Hadjar,RBR,2,18.1,11,118
|
|
78
|
-
driver,LAW,L. Lawson,RBS,2,16.5,13,142
|
|
79
|
-
driver,SAI,C. Sainz Jr,WIL,2,15.9,12,123
|
|
80
|
-
driver,BEA,O. Bearman,HAS,2,13.2,15,186
|
|
81
|
-
driver,STR,L. Stroll,AMR,2,13,13,75
|
|
82
|
-
driver,ALB,A. Albon,WIL,2,11.9,15,68
|
|
83
|
-
driver,HUL,N. Hulkenberg,AUD,2,11.8,16,81
|
|
84
|
-
driver,OCO,E. Ocon,HAS,2,10.7,17,124
|
|
85
|
-
driver,BOR,G. Bortoleto,AUD,2,10.5,16,90
|
|
86
|
-
driver,COL,F. Colapinto,ALP,2,8.7,18,130
|
|
87
|
-
driver,LIN,A. Lindblad,RBS,2,8.6,17,143
|
|
88
|
-
driver,PER,S. Perez,CAD,2,7.3,19,102
|
|
89
|
-
driver,BOT,V. Bottas,CAD,2,6.5,19,94
|
|
90
|
-
team,MER,MER,,2,29.1,,177
|
|
91
|
-
team,FER,FER,,2,24.6,,163
|
|
92
|
-
team,MCL,MCL,,2,22.7,,77
|
|
93
|
-
team,RBR,RBR,,2,21.7,,110
|
|
94
|
-
team,RBS,RBS,,2,17.3,,123
|
|
95
|
-
team,ALP,ALP,,2,16.8,,121
|
|
96
|
-
team,AMR,AMR,,2,15.7,,72
|
|
97
|
-
team,WIL,WIL,,2,13.8,,78
|
|
98
|
-
team,HAS,HAS,,2,11,,125
|
|
99
|
-
team,AUD,AUD,,2,9.7,,80
|
|
100
|
-
team,CAD,CAD,,2,9,,83
|
|
101
|
-
driver,RUS,G. Russell,MER,3,29.5,3,164
|
|
102
|
-
driver,ANT,K. Antonelli,MER,3,28.7,4,173
|
|
103
|
-
driver,LEC,C. Leclerc,FER,3,26.3,5,162
|
|
104
|
-
driver,NOR,L. Norris,MCL,3,24.7,6,118
|
|
105
|
-
driver,VER,M. Verstappen,RBR,3,24.6,5,133
|
|
106
|
-
driver,PIA,O. Piastri,MCL,3,24.1,8,91
|
|
107
|
-
driver,HAM,L. Hamilton,FER,3,23.4,7,158
|
|
108
|
-
driver,GAS,P. Gasly,ALP,3,21.7,10,143
|
|
109
|
-
driver,LAW,L. Lawson,RBS,3,18,12,140
|
|
110
|
-
driver,HAD,I. Hadjar,RBR,3,17.7,11,117
|
|
111
|
-
driver,ALO,F. Alonso,AMR,3,16.2,11,79
|
|
112
|
-
driver,SAI,C. Sainz Jr,WIL,3,14.9,13,115
|
|
113
|
-
driver,HUL,N. Hulkenberg,AUD,3,13.3,15,95
|
|
114
|
-
driver,OCO,E. Ocon,HAS,3,12.7,16,130
|
|
115
|
-
driver,BOR,G. Bortoleto,AUD,3,11.5,16,98
|
|
116
|
-
driver,BEA,O. Bearman,HAS,3,11.2,15,142
|
|
117
|
-
driver,STR,L. Stroll,AMR,3,11,14,69
|
|
118
|
-
driver,ALB,A. Albon,WIL,3,9.9,16,70
|
|
119
|
-
driver,LIN,A. Lindblad,RBS,3,9.7,17,131
|
|
120
|
-
driver,COL,F. Colapinto,ALP,3,9,17,117
|
|
121
|
-
driver,PER,S. Perez,CAD,3,7.5,18,97
|
|
122
|
-
driver,BOT,V. Bottas,CAD,3,6.2,19,87
|
|
123
|
-
team,MER,MER,,3,29.3,,175
|
|
124
|
-
team,FER,FER,,3,24.6,,161
|
|
125
|
-
team,MCL,MCL,,3,23.8,,106
|
|
126
|
-
team,RBR,RBR,,3,21.8,,116
|
|
127
|
-
team,ALP,ALP,,3,17.5,,120
|
|
128
|
-
team,RBS,RBS,,3,17.3,,120
|
|
129
|
-
team,AMR,AMR,,3,12.8,,69
|
|
130
|
-
team,WIL,WIL,,3,12.7,,80
|
|
131
|
-
team,HAS,HAS,,3,11.2,,114
|
|
132
|
-
team,AUD,AUD,,3,10.8,,92
|
|
133
|
-
team,CAD,CAD,,3,8.4,,80
|
|
134
|
-
driver,ANT,K. Antonelli,MER,4,28.8,4,176
|
|
135
|
-
driver,RUS,G. Russell,MER,4,28.7,3,165
|
|
136
|
-
driver,NOR,L. Norris,MCL,4,26.7,6,136
|
|
137
|
-
driver,LEC,C. Leclerc,FER,4,25.9,6,161
|
|
138
|
-
driver,PIA,O. Piastri,MCL,4,25.7,8,114
|
|
139
|
-
driver,VER,M. Verstappen,RBR,4,25.3,5,144
|
|
140
|
-
driver,HAM,L. Hamilton,FER,4,23.3,7,157
|
|
141
|
-
driver,GAS,P. Gasly,ALP,4,19.7,11,130
|
|
142
|
-
driver,SAI,C. Sainz Jr,WIL,4,16.4,12,122
|
|
143
|
-
driver,LAW,L. Lawson,RBS,4,16,13,126
|
|
144
|
-
driver,HAD,I. Hadjar,RBR,4,15.7,13,100
|
|
145
|
-
driver,ALO,F. Alonso,AMR,4,15.1,12,85
|
|
146
|
-
driver,OCO,E. Ocon,HAS,4,13.2,15,127
|
|
147
|
-
driver,BEA,O. Bearman,HAS,4,12.9,15,140
|
|
148
|
-
driver,BOR,G. Bortoleto,AUD,4,12.7,15,105
|
|
149
|
-
driver,ALB,A. Albon,WIL,4,11.9,15,87
|
|
150
|
-
driver,HUL,N. Hulkenberg,AUD,4,11.3,16,91
|
|
151
|
-
driver,COL,F. Colapinto,ALP,4,11,16,135
|
|
152
|
-
driver,LIN,A. Lindblad,RBS,4,10.5,16,125
|
|
153
|
-
driver,STR,L. Stroll,AMR,4,10.4,15,74
|
|
154
|
-
driver,PER,S. Perez,CAD,4,8.1,18,98
|
|
155
|
-
driver,BOT,V. Bottas,CAD,4,6,19,85
|
|
156
|
-
team,MER,MER,,4,29.4,,174
|
|
157
|
-
team,MCL,MCL,,4,24.7,,120
|
|
158
|
-
team,FER,FER,,4,24.6,,158
|
|
159
|
-
team,RBR,RBR,,4,20,,111
|
|
160
|
-
team,ALP,ALP,,4,18,,118
|
|
161
|
-
team,RBS,RBS,,4,15.3,,113
|
|
162
|
-
team,WIL,WIL,,4,15,,90
|
|
163
|
-
team,HAS,HAS,,4,12.6,,113
|
|
164
|
-
team,AMR,AMR,,4,11.3,,74
|
|
165
|
-
team,AUD,AUD,,4,11,,92
|
|
166
|
-
team,CAD,CAD,,4,7.3,,80
|
|
1
|
+
type,driver_abbr,driver_name,driver_team,round,starting_salary,eight_race_average,points_from_last_race
|
|
2
|
+
driver,VER,M. Verstappen,RBR,0,30,1,
|
|
3
|
+
driver,RUS,G. Russell,MER,0,28.7,2,
|
|
4
|
+
driver,NOR,L. Norris,MCL,0,27.4,3,
|
|
5
|
+
driver,PIA,O. Piastri,MCL,0,26.1,4,
|
|
6
|
+
driver,ANT,K. Antonelli,MER,0,24.8,5,
|
|
7
|
+
driver,LEC,C. Leclerc,FER,0,23.5,6,
|
|
8
|
+
driver,ALO,F. Alonso,AMR,0,22.2,7,
|
|
9
|
+
driver,HAM,L. Hamilton,FER,0,20.9,8,
|
|
10
|
+
driver,HAD,I. Hadjar,RBR,0,19.6,9,
|
|
11
|
+
driver,GAS,P. Gasly,ALP,0,18.3,10,
|
|
12
|
+
driver,STR,L. Stroll,AMR,0,17,11,
|
|
13
|
+
driver,SAI,C. Sainz Jr,WIL,0,15.7,12,
|
|
14
|
+
driver,LAW,L. Lawson,RBS,0,14.4,13,
|
|
15
|
+
driver,ALB,A. Albon,WIL,0,13.1,14,
|
|
16
|
+
driver,HUL,N. Hulkenberg,AUD,0,11.8,15,
|
|
17
|
+
driver,BOR,G. Bortoleto,AUD,0,10.5,16,
|
|
18
|
+
driver,BEA,O. Bearman,HAS,0,9.2,17,
|
|
19
|
+
driver,OCO,E. Ocon,HAS,0,7.9,18,
|
|
20
|
+
driver,BOT,V. Bottas,CAD,0,4.7,19,
|
|
21
|
+
driver,PER,S. Perez,CAD,0,4.7,19,
|
|
22
|
+
driver,COL,F. Colapinto,ALP,0,4.7,19,
|
|
23
|
+
driver,LIN,A. Lindblad,RBS,0,4.6,19,
|
|
24
|
+
team,MER,MER,,0,28.5,1,
|
|
25
|
+
team,MCL,MCL,,0,28.5,2,
|
|
26
|
+
team,RBR,RBR,,0,25,3,
|
|
27
|
+
team,FER,FER,,0,22.5,4,
|
|
28
|
+
team,AMR,AMR,,0,20,5,
|
|
29
|
+
team,WIL,WIL,,0,17.5,6,
|
|
30
|
+
team,RBS,RBS,,0,15,7,
|
|
31
|
+
team,ALP,ALP,,0,12.5,8,
|
|
32
|
+
team,AUD,AUD,,0,10,9,
|
|
33
|
+
team,CAD,CAD,,0,7.5,10,
|
|
34
|
+
team,HAS,HAS,,0,5,11,
|
|
35
|
+
driver,VER,M. Verstappen,RBR,1,28.2,2,
|
|
36
|
+
driver,RUS,G. Russell,MER,1,29.6,2,
|
|
37
|
+
driver,NOR,L. Norris,MCL,1,26.7,4,
|
|
38
|
+
driver,PIA,O. Piastri,MCL,1,24.1,7,
|
|
39
|
+
driver,ANT,K. Antonelli,MER,1,25.9,5,
|
|
40
|
+
driver,LEC,C. Leclerc,FER,1,24.5,6,
|
|
41
|
+
driver,ALO,F. Alonso,AMR,1,20.2,9,
|
|
42
|
+
driver,HAM,L. Hamilton,FER,1,22.1,8,
|
|
43
|
+
driver,HAD,I. Hadjar,RBR,1,17.6,11,
|
|
44
|
+
driver,GAS,P. Gasly,ALP,1,18.3,10,
|
|
45
|
+
driver,STR,L. Stroll,AMR,1,15,12,
|
|
46
|
+
driver,SAI,C. Sainz Jr,WIL,1,13.9,13,
|
|
47
|
+
driver,LAW,L. Lawson,RBS,1,14.5,13,
|
|
48
|
+
driver,ALB,A. Albon,WIL,1,13.9,14,
|
|
49
|
+
driver,HUL,N. Hulkenberg,AUD,1,9.8,16,
|
|
50
|
+
driver,BOR,G. Bortoleto,AUD,1,12.5,16,
|
|
51
|
+
driver,BEA,O. Bearman,HAS,1,11.2,16,
|
|
52
|
+
driver,OCO,E. Ocon,HAS,1,9.9,18,
|
|
53
|
+
driver,BOT,V. Bottas,CAD,1,4.5,19,
|
|
54
|
+
driver,PER,S. Perez,CAD,1,6.4,19,
|
|
55
|
+
driver,COL,F. Colapinto,ALP,1,6.7,19,
|
|
56
|
+
driver,LIN,A. Lindblad,RBS,1,6.6,18,
|
|
57
|
+
team,MER,MER,,1,28.8,,
|
|
58
|
+
team,MCL,MCL,,1,25.7,,
|
|
59
|
+
team,RBR,RBR,,1,22.4,,
|
|
60
|
+
team,FER,FER,,1,23.7,,
|
|
61
|
+
team,AMR,AMR,,1,17,,
|
|
62
|
+
team,WIL,WIL,,1,16.1,,
|
|
63
|
+
team,RBS,RBS,,1,17.4,,
|
|
64
|
+
team,ALP,ALP,,1,14.2,,
|
|
65
|
+
team,AUD,AUD,,1,9.8,,
|
|
66
|
+
team,CAD,CAD,,1,7.3,,
|
|
67
|
+
team,HAS,HAS,,1,8,,
|
|
68
|
+
driver,RUS,G. Russell,MER,2,29.5,2,171
|
|
69
|
+
driver,ANT,K. Antonelli,MER,2,27.5,5,174
|
|
70
|
+
driver,VER,M. Verstappen,RBR,2,26.2,4,132
|
|
71
|
+
driver,LEC,C. Leclerc,FER,2,24.8,6,164
|
|
72
|
+
driver,NOR,L. Norris,MCL,2,24.7,6,107
|
|
73
|
+
driver,HAM,L. Hamilton,FER,2,24.1,7,169
|
|
74
|
+
driver,PIA,O. Piastri,MCL,2,22.1,8,50
|
|
75
|
+
driver,GAS,P. Gasly,ALP,2,19.8,10,143
|
|
76
|
+
driver,ALO,F. Alonso,AMR,2,18.2,10,78
|
|
77
|
+
driver,HAD,I. Hadjar,RBR,2,18.1,11,118
|
|
78
|
+
driver,LAW,L. Lawson,RBS,2,16.5,13,142
|
|
79
|
+
driver,SAI,C. Sainz Jr,WIL,2,15.9,12,123
|
|
80
|
+
driver,BEA,O. Bearman,HAS,2,13.2,15,186
|
|
81
|
+
driver,STR,L. Stroll,AMR,2,13,13,75
|
|
82
|
+
driver,ALB,A. Albon,WIL,2,11.9,15,68
|
|
83
|
+
driver,HUL,N. Hulkenberg,AUD,2,11.8,16,81
|
|
84
|
+
driver,OCO,E. Ocon,HAS,2,10.7,17,124
|
|
85
|
+
driver,BOR,G. Bortoleto,AUD,2,10.5,16,90
|
|
86
|
+
driver,COL,F. Colapinto,ALP,2,8.7,18,130
|
|
87
|
+
driver,LIN,A. Lindblad,RBS,2,8.6,17,143
|
|
88
|
+
driver,PER,S. Perez,CAD,2,7.3,19,102
|
|
89
|
+
driver,BOT,V. Bottas,CAD,2,6.5,19,94
|
|
90
|
+
team,MER,MER,,2,29.1,,177
|
|
91
|
+
team,FER,FER,,2,24.6,,163
|
|
92
|
+
team,MCL,MCL,,2,22.7,,77
|
|
93
|
+
team,RBR,RBR,,2,21.7,,110
|
|
94
|
+
team,RBS,RBS,,2,17.3,,123
|
|
95
|
+
team,ALP,ALP,,2,16.8,,121
|
|
96
|
+
team,AMR,AMR,,2,15.7,,72
|
|
97
|
+
team,WIL,WIL,,2,13.8,,78
|
|
98
|
+
team,HAS,HAS,,2,11,,125
|
|
99
|
+
team,AUD,AUD,,2,9.7,,80
|
|
100
|
+
team,CAD,CAD,,2,9,,83
|
|
101
|
+
driver,RUS,G. Russell,MER,3,29.5,3,164
|
|
102
|
+
driver,ANT,K. Antonelli,MER,3,28.7,4,173
|
|
103
|
+
driver,LEC,C. Leclerc,FER,3,26.3,5,162
|
|
104
|
+
driver,NOR,L. Norris,MCL,3,24.7,6,118
|
|
105
|
+
driver,VER,M. Verstappen,RBR,3,24.6,5,133
|
|
106
|
+
driver,PIA,O. Piastri,MCL,3,24.1,8,91
|
|
107
|
+
driver,HAM,L. Hamilton,FER,3,23.4,7,158
|
|
108
|
+
driver,GAS,P. Gasly,ALP,3,21.7,10,143
|
|
109
|
+
driver,LAW,L. Lawson,RBS,3,18,12,140
|
|
110
|
+
driver,HAD,I. Hadjar,RBR,3,17.7,11,117
|
|
111
|
+
driver,ALO,F. Alonso,AMR,3,16.2,11,79
|
|
112
|
+
driver,SAI,C. Sainz Jr,WIL,3,14.9,13,115
|
|
113
|
+
driver,HUL,N. Hulkenberg,AUD,3,13.3,15,95
|
|
114
|
+
driver,OCO,E. Ocon,HAS,3,12.7,16,130
|
|
115
|
+
driver,BOR,G. Bortoleto,AUD,3,11.5,16,98
|
|
116
|
+
driver,BEA,O. Bearman,HAS,3,11.2,15,142
|
|
117
|
+
driver,STR,L. Stroll,AMR,3,11,14,69
|
|
118
|
+
driver,ALB,A. Albon,WIL,3,9.9,16,70
|
|
119
|
+
driver,LIN,A. Lindblad,RBS,3,9.7,17,131
|
|
120
|
+
driver,COL,F. Colapinto,ALP,3,9,17,117
|
|
121
|
+
driver,PER,S. Perez,CAD,3,7.5,18,97
|
|
122
|
+
driver,BOT,V. Bottas,CAD,3,6.2,19,87
|
|
123
|
+
team,MER,MER,,3,29.3,,175
|
|
124
|
+
team,FER,FER,,3,24.6,,161
|
|
125
|
+
team,MCL,MCL,,3,23.8,,106
|
|
126
|
+
team,RBR,RBR,,3,21.8,,116
|
|
127
|
+
team,ALP,ALP,,3,17.5,,120
|
|
128
|
+
team,RBS,RBS,,3,17.3,,120
|
|
129
|
+
team,AMR,AMR,,3,12.8,,69
|
|
130
|
+
team,WIL,WIL,,3,12.7,,80
|
|
131
|
+
team,HAS,HAS,,3,11.2,,114
|
|
132
|
+
team,AUD,AUD,,3,10.8,,92
|
|
133
|
+
team,CAD,CAD,,3,8.4,,80
|
|
134
|
+
driver,ANT,K. Antonelli,MER,4,28.8,4,176
|
|
135
|
+
driver,RUS,G. Russell,MER,4,28.7,3,165
|
|
136
|
+
driver,NOR,L. Norris,MCL,4,26.7,6,136
|
|
137
|
+
driver,LEC,C. Leclerc,FER,4,25.9,6,161
|
|
138
|
+
driver,PIA,O. Piastri,MCL,4,25.7,8,114
|
|
139
|
+
driver,VER,M. Verstappen,RBR,4,25.3,5,144
|
|
140
|
+
driver,HAM,L. Hamilton,FER,4,23.3,7,157
|
|
141
|
+
driver,GAS,P. Gasly,ALP,4,19.7,11,130
|
|
142
|
+
driver,SAI,C. Sainz Jr,WIL,4,16.4,12,122
|
|
143
|
+
driver,LAW,L. Lawson,RBS,4,16,13,126
|
|
144
|
+
driver,HAD,I. Hadjar,RBR,4,15.7,13,100
|
|
145
|
+
driver,ALO,F. Alonso,AMR,4,15.1,12,85
|
|
146
|
+
driver,OCO,E. Ocon,HAS,4,13.2,15,127
|
|
147
|
+
driver,BEA,O. Bearman,HAS,4,12.9,15,140
|
|
148
|
+
driver,BOR,G. Bortoleto,AUD,4,12.7,15,105
|
|
149
|
+
driver,ALB,A. Albon,WIL,4,11.9,15,87
|
|
150
|
+
driver,HUL,N. Hulkenberg,AUD,4,11.3,16,91
|
|
151
|
+
driver,COL,F. Colapinto,ALP,4,11,16,135
|
|
152
|
+
driver,LIN,A. Lindblad,RBS,4,10.5,16,125
|
|
153
|
+
driver,STR,L. Stroll,AMR,4,10.4,15,74
|
|
154
|
+
driver,PER,S. Perez,CAD,4,8.1,18,98
|
|
155
|
+
driver,BOT,V. Bottas,CAD,4,6,19,85
|
|
156
|
+
team,MER,MER,,4,29.4,,174
|
|
157
|
+
team,MCL,MCL,,4,24.7,,120
|
|
158
|
+
team,FER,FER,,4,24.6,,158
|
|
159
|
+
team,RBR,RBR,,4,20,,111
|
|
160
|
+
team,ALP,ALP,,4,18,,118
|
|
161
|
+
team,RBS,RBS,,4,15.3,,113
|
|
162
|
+
team,WIL,WIL,,4,15,,90
|
|
163
|
+
team,HAS,HAS,,4,12.6,,113
|
|
164
|
+
team,AMR,AMR,,4,11.3,,74
|
|
165
|
+
team,AUD,AUD,,4,11,,92
|
|
166
|
+
team,CAD,CAD,,4,7.3,,80
|
|
167
|
+
driver,ANT,K. Antonelli,MER,5,30.1,,180
|
|
168
|
+
driver,RUS,G. Russell,MER,5,26.7,,156
|
|
169
|
+
driver,VER,M. Verstappen,RBR,5,26.2,,150
|
|
170
|
+
driver,LEC,C. Leclerc,FER,5,25.9,,163
|
|
171
|
+
driver,HAM,L. Hamilton,FER,5,25.3,,163
|
|
172
|
+
driver,NOR,L. Norris,MCL,5,24.7,,133
|
|
173
|
+
driver,PIA,O. Piastri,MCL,5,24.6,,121
|
|
174
|
+
driver,GAS,P. Gasly,ALP,5,19.3,,132
|
|
175
|
+
driver,SAI,C. Sainz Jr,WIL,5,18,,128
|
|
176
|
+
driver,LAW,L. Lawson,RBS,5,18,,135
|
|
177
|
+
driver,HAD,I. Hadjar,RBR,5,17.7,,113
|
|
178
|
+
driver,BEA,O. Bearman,HAS,5,14.5,,140
|
|
179
|
+
driver,ALO,F. Alonso,AMR,5,13.1,,80
|
|
180
|
+
driver,COL,F. Colapinto,ALP,5,13,,145
|
|
181
|
+
driver,HUL,N. Hulkenberg,AUD,5,12.5,,98
|
|
182
|
+
driver,BOR,G. Bortoleto,AUD,5,12.5,,107
|
|
183
|
+
driver,OCO,E. Ocon,HAS,5,12.4,,124
|
|
184
|
+
driver,STR,L. Stroll,AMR,5,9.9,,81
|
|
185
|
+
driver,ALB,A. Albon,WIL,5,9.9,,81
|
|
186
|
+
driver,LIN,A. Lindblad,RBS,5,8.5,,110
|
|
187
|
+
driver,PER,S. Perez,CAD,5,7.4,,96
|
|
188
|
+
driver,BOT,V. Bottas,CAD,5,6.2,,89
|
|
189
|
+
team,MER,MER,,5,28.3,,168
|
|
190
|
+
team,FER,FER,,5,25.9,,158
|
|
191
|
+
team,MCL,MCL,,5,23.5,,120
|
|
192
|
+
team,RBR,RBR,,5,21.8,,120
|
|
193
|
+
team,ALP,ALP,,5,19,,121
|
|
194
|
+
team,WIL,WIL,,5,14.2,,90
|
|
195
|
+
team,RBS,RBS,,5,13.8,,108
|
|
196
|
+
team,HAS,HAS,,5,13,,111
|
|
197
|
+
team,AUD,AUD,,5,12.5,,96
|
|
198
|
+
team,AMR,AMR,,5,9.5,,74
|
|
199
|
+
team,CAD,CAD,,5,7.2,,79
|
|
200
|
+
driver,ANT,K. Antonelli,MER,6,29.9,,179
|
|
201
|
+
driver,HAM,L. Hamilton,FER,6,27,,165
|
|
202
|
+
driver,PIA,O. Piastri,MCL,6,25.3,,130
|
|
203
|
+
driver,RUS,G. Russell,MER,6,24.7,,150
|
|
204
|
+
driver,VER,M. Verstappen,RBR,6,24.2,,139
|
|
205
|
+
driver,LEC,C. Leclerc,FER,6,23.9,,153
|
|
206
|
+
driver,NOR,L. Norris,MCL,6,22.7,,125
|
|
207
|
+
driver,LAW,L. Lawson,RBS,6,20,,140
|
|
208
|
+
driver,GAS,P. Gasly,ALP,6,19.7,,134
|
|
209
|
+
driver,HAD,I. Hadjar,RBR,6,19.7,,126
|
|
210
|
+
driver,SAI,C. Sainz Jr,WIL,6,16,,122
|
|
211
|
+
driver,ALO,F. Alonso,AMR,6,14.7,,90
|
|
212
|
+
driver,OCO,E. Ocon,HAS,6,14.4,,128
|
|
213
|
+
driver,BOR,G. Bortoleto,AUD,6,13.8,,110
|
|
214
|
+
driver,HUL,N. Hulkenberg,AUD,6,12.6,,99
|
|
215
|
+
driver,BEA,O. Bearman,HAS,6,12.5,,127
|
|
216
|
+
driver,COL,F. Colapinto,ALP,6,12.3,,137
|
|
217
|
+
driver,ALB,A. Albon,WIL,6,11.9,,94
|
|
218
|
+
driver,LIN,A. Lindblad,RBS,6,10.5,,121
|
|
219
|
+
driver,PER,S. Perez,CAD,6,8.4,,97
|
|
220
|
+
driver,STR,L. Stroll,AMR,6,8.4,,80
|
|
221
|
+
driver,BOT,V. Bottas,CAD,6,4.8,,83
|
|
222
|
+
team,MER,MER,,6,28.7,,165
|
|
223
|
+
team,FER,FER,,6,26.2,,155
|
|
224
|
+
team,MCL,MCL,,6,22.6,,121
|
|
225
|
+
team,RBR,RBR,,6,21.9,,122
|
|
226
|
+
team,ALP,ALP,,6,18.5,,121
|
|
227
|
+
team,RBS,RBS,,6,16.5,,113
|
|
228
|
+
team,WIL,WIL,,6,14.2,,94
|
|
229
|
+
team,AUD,AUD,,6,12.4,,98
|
|
230
|
+
team,HAS,HAS,,6,12.1,,108
|
|
231
|
+
team,AMR,AMR,,6,8.8,,76
|
|
232
|
+
team,CAD,CAD,,6,6.4,,79
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
round,driver_abbr,finishing_position
|
|
2
|
+
1,RUS,1
|
|
3
|
+
1,ANT,2
|
|
4
|
+
1,LEC,3
|
|
5
|
+
1,HAM,4
|
|
6
|
+
1,NOR,5
|
|
7
|
+
1,VER,6
|
|
8
|
+
1,BEA,7
|
|
9
|
+
1,LIN,8
|
|
10
|
+
1,BOR,9
|
|
11
|
+
1,GAS,10
|
|
12
|
+
1,OCO,11
|
|
13
|
+
1,ALB,12
|
|
14
|
+
1,LAW,13
|
|
15
|
+
1,COL,14
|
|
16
|
+
1,SAI,15
|
|
17
|
+
1,PER,16
|
|
18
|
+
1,STR,17
|
|
19
|
+
1,ALO,18
|
|
20
|
+
1,BOT,19
|
|
21
|
+
1,HAD,20
|
|
22
|
+
1,PIA,21
|
|
23
|
+
1,HUL,22
|
|
24
|
+
2,ANT,1
|
|
25
|
+
2,RUS,2
|
|
26
|
+
2,HAM,3
|
|
27
|
+
2,LEC,4
|
|
28
|
+
2,BEA,5
|
|
29
|
+
2,GAS,6
|
|
30
|
+
2,LAW,7
|
|
31
|
+
2,HAD,8
|
|
32
|
+
2,SAI,9
|
|
33
|
+
2,COL,10
|
|
34
|
+
2,HUL,11
|
|
35
|
+
2,LIN,12
|
|
36
|
+
2,BOT,13
|
|
37
|
+
2,OCO,14
|
|
38
|
+
2,PER,15
|
|
39
|
+
2,VER,16
|
|
40
|
+
2,ALO,17
|
|
41
|
+
2,STR,18
|
|
42
|
+
2,PIA,19
|
|
43
|
+
2,NOR,20
|
|
44
|
+
2,BOR,21
|
|
45
|
+
2,ALB,22
|
|
46
|
+
3,ANT,1
|
|
47
|
+
3,PIA,2
|
|
48
|
+
3,LEC,3
|
|
49
|
+
3,RUS,4
|
|
50
|
+
3,NOR,5
|
|
51
|
+
3,HAM,6
|
|
52
|
+
3,GAS,7
|
|
53
|
+
3,VER,8
|
|
54
|
+
3,LAW,9
|
|
55
|
+
3,OCO,10
|
|
56
|
+
3,HUL,11
|
|
57
|
+
3,HAD,12
|
|
58
|
+
3,BOR,13
|
|
59
|
+
3,LIN,14
|
|
60
|
+
3,SAI,15
|
|
61
|
+
3,COL,16
|
|
62
|
+
3,PER,17
|
|
63
|
+
3,ALO,18
|
|
64
|
+
3,BOT,19
|
|
65
|
+
3,ALB,20
|
|
66
|
+
3,STR,21
|
|
67
|
+
3,BEA,22
|
|
68
|
+
4,ANT,1
|
|
69
|
+
4,NOR,2
|
|
70
|
+
4,PIA,3
|
|
71
|
+
4,RUS,4
|
|
72
|
+
4,VER,5
|
|
73
|
+
4,HAM,6
|
|
74
|
+
4,COL,7
|
|
75
|
+
4,LEC,8
|
|
76
|
+
4,SAI,9
|
|
77
|
+
4,ALB,10
|
|
78
|
+
4,BEA,11
|
|
79
|
+
4,BOR,12
|
|
80
|
+
4,OCO,13
|
|
81
|
+
4,LIN,14
|
|
82
|
+
4,ALO,15
|
|
83
|
+
4,PER,16
|
|
84
|
+
4,STR,17
|
|
85
|
+
4,BOT,18
|
|
86
|
+
4,HUL,19
|
|
87
|
+
4,LAW,20
|
|
88
|
+
4,GAS,21
|
|
89
|
+
4,HAD,22
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gr_analytics
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Scoring and salary calculation for GridRival fantasy F1
|
|
5
5
|
Author: nce8
|
|
6
6
|
License-Expression: MIT
|
|
@@ -135,6 +135,31 @@ Bundled driver data (`gr_analytics/data/driver_data.csv`) contains starting sala
|
|
|
135
135
|
- `round=0` — pre-season (before Australia 2026)
|
|
136
136
|
- `round=1` — post-Australia 2026
|
|
137
137
|
|
|
138
|
+
## Eight-Race Average
|
|
139
|
+
|
|
140
|
+
GridRival's "8 race average" can be computed instead of entered by hand.
|
|
141
|
+
GridRival seeds the season with 8 slots holding a hard-coded initial
|
|
142
|
+
average (the `round=0` values in driver_data); each race replaces one
|
|
143
|
+
slot with the driver's classified finishing position, and the displayed
|
|
144
|
+
value is the **ceiling** of the slot mean. Race finishing positions live
|
|
145
|
+
in `gr_analytics/data/race_results.csv`.
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from gr_analytics import calculate_eight_race_averages, eight_race_average
|
|
149
|
+
|
|
150
|
+
# All drivers, after the latest round in race_results.csv
|
|
151
|
+
calculate_eight_race_averages()
|
|
152
|
+
|
|
153
|
+
# All drivers, after round 2
|
|
154
|
+
calculate_eight_race_averages(through_round=2)
|
|
155
|
+
|
|
156
|
+
# Single driver from scratch: seed 1, finished P6 then P16
|
|
157
|
+
eight_race_average(1, [6, 16])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This reproduces GridRival's displayed values exactly for all rounds so
|
|
161
|
+
far (verified in `tests/test_eight_race_average.py`).
|
|
162
|
+
|
|
138
163
|
## Lineup Optimisation
|
|
139
164
|
|
|
140
165
|
`optimal_lineup` uses mixed-integer linear programming (via `scipy.optimize.milp`) to find the best 5-driver + 1-constructor lineup within a salary budget.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for GridRival eight-race average calculation.
|
|
3
|
+
|
|
4
|
+
Run with: pytest tests/test_eight_race_average.py -v
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from gr_analytics import (
|
|
13
|
+
calculate_eight_race_averages,
|
|
14
|
+
driver_data,
|
|
15
|
+
eight_race_average,
|
|
16
|
+
race_results,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
_TESTS_DIR = Path(__file__).parent
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Pure function tests (hand-calculated)
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TestEightRaceAverage:
|
|
28
|
+
def test_no_races_returns_seed(self):
|
|
29
|
+
assert eight_race_average(5, []) == 5
|
|
30
|
+
|
|
31
|
+
def test_one_race_hand_calculated(self):
|
|
32
|
+
# VER, Australia 2026: seed 1, finished P6
|
|
33
|
+
# (7*1 + 6) / 8 = 1.625 -> ceil -> 2
|
|
34
|
+
assert eight_race_average(1, [6]) == 2
|
|
35
|
+
|
|
36
|
+
def test_uses_ceiling_not_rounding(self):
|
|
37
|
+
# NOR, Australia 2026: seed 3, finished P5
|
|
38
|
+
# (7*3 + 5) / 8 = 3.25 -> ceil -> 4 (rounding would give 3)
|
|
39
|
+
assert eight_race_average(3, [5]) == 4
|
|
40
|
+
|
|
41
|
+
def test_exact_integer_unchanged(self):
|
|
42
|
+
# GAS, Australia 2026: seed 10, finished P10
|
|
43
|
+
# (7*10 + 10) / 8 = 10.0 exactly
|
|
44
|
+
assert eight_race_average(10, [10]) == 10
|
|
45
|
+
|
|
46
|
+
def test_two_races_hand_calculated(self):
|
|
47
|
+
# LIN, 2026: seed 19, finished P8 then P12
|
|
48
|
+
# (6*19 + 8 + 12) / 8 = 16.75 -> ceil -> 17
|
|
49
|
+
assert eight_race_average(19, [8, 12]) == 17
|
|
50
|
+
|
|
51
|
+
def test_seed_fully_rolls_off_after_eight_races(self):
|
|
52
|
+
# After 8 races the seed should not matter at all
|
|
53
|
+
positions = [1, 2, 3, 4, 5, 6, 7, 8] # mean 4.5 -> ceil 5
|
|
54
|
+
assert eight_race_average(22, positions) == 5
|
|
55
|
+
assert eight_race_average(1, positions) == 5
|
|
56
|
+
|
|
57
|
+
def test_only_last_eight_races_count(self):
|
|
58
|
+
# First race (P22) falls out of the window on race 9
|
|
59
|
+
positions = [22] + [4] * 8
|
|
60
|
+
assert eight_race_average(10, positions) == 4
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
# Agreement with GridRival's displayed values (driver_data.csv)
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _rounds_with_recorded_averages():
|
|
69
|
+
"""Rounds whose driver rows have GridRival eight_race_average values.
|
|
70
|
+
|
|
71
|
+
Later rounds may be entered with only salary/points (eight_race_average
|
|
72
|
+
left blank until the corresponding race_results are added), so we only
|
|
73
|
+
check rounds where GridRival's own values exist to compare against.
|
|
74
|
+
"""
|
|
75
|
+
dd = driver_data()
|
|
76
|
+
drivers = dd[dd["type"] == "driver"]
|
|
77
|
+
have_values = drivers.groupby("round")["eight_race_average"].apply(
|
|
78
|
+
lambda s: s.notna().all()
|
|
79
|
+
)
|
|
80
|
+
return sorted(have_values[have_values].index)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TestAgreementWithGridRival:
|
|
84
|
+
@pytest.mark.parametrize("rnd", _rounds_with_recorded_averages())
|
|
85
|
+
def test_matches_driver_data_sheet(self, rnd):
|
|
86
|
+
"""Computed averages must equal GridRival's values for every round."""
|
|
87
|
+
dd = driver_data()
|
|
88
|
+
sheet = (
|
|
89
|
+
dd[(dd["type"] == "driver") & (dd["round"] == rnd)]
|
|
90
|
+
.set_index("driver_abbr")["eight_race_average"]
|
|
91
|
+
.sort_index()
|
|
92
|
+
)
|
|
93
|
+
computed = calculate_eight_race_averages(through_round=rnd).sort_index()
|
|
94
|
+
|
|
95
|
+
mismatches = sheet[sheet != computed]
|
|
96
|
+
assert mismatches.empty, (
|
|
97
|
+
f"Round {rnd} mismatches (sheet vs computed):\n"
|
|
98
|
+
f"{pd.DataFrame({'sheet': mismatches, 'computed': computed[mismatches.index]})}"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def test_default_round_is_latest(self):
|
|
102
|
+
latest = race_results()["round"].max()
|
|
103
|
+
pd.testing.assert_series_equal(
|
|
104
|
+
calculate_eight_race_averages(),
|
|
105
|
+
calculate_eight_race_averages(through_round=latest),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# ---------------------------------------------------------------------------
|
|
110
|
+
# race_results.csv data integrity
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class TestRaceResultsData:
|
|
115
|
+
def test_positions_complete_each_round(self):
|
|
116
|
+
rr = race_results()
|
|
117
|
+
for rnd, group in rr.groupby("round"):
|
|
118
|
+
positions = sorted(group["finishing_position"])
|
|
119
|
+
assert positions == list(range(1, len(group) + 1)), (
|
|
120
|
+
f"Round {rnd} positions are not a complete 1..n sequence"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def test_round_one_matches_australia_fixture(self):
|
|
124
|
+
"""Race 1 positions must agree with the Australia scenario fixture."""
|
|
125
|
+
australia = pd.read_csv(_TESTS_DIR / "test_australia.csv").set_index(
|
|
126
|
+
"driver_abbr"
|
|
127
|
+
)
|
|
128
|
+
rr = race_results()
|
|
129
|
+
round_one = rr[rr["round"] == 1].set_index("driver_abbr")
|
|
130
|
+
for abbr, expected in australia["finishing_position"].items():
|
|
131
|
+
assert round_one.at[abbr, "finishing_position"] == expected
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|