SoccerPredictAI
  • Home
  • Reports
    • 01 · EDA & Preprocessing
    • 02 · Feature Engineering
    • 03 · Experiment Studies v1.01–v1.05
    • 04 · Model Analysis
    • 05 · Holdout Analysis
    • 06 · Live Inference & Odds
    • 07 · Live Betting Strategy
  • Back to Docs (MkDocs)

On this page

  • 0. Bet365 odds data — load_odds_fdco
  • 1. Overall model quality (holdout set)
  • 2. Model quality by region
  • 3. Model quality by ELO gap
  • 4. ROI simulation — Bet365 closing odds benchmark
  • 5. ROI by region
  • 6. ROI by minimum edge threshold
  • 7. Model quality by season

Holdout Analysis — Model Performance & ROI Simulation

Error analysis on holdout set + Bet365 closing odds ROI benchmark

Author

Dima Ivanov

Published

May 28, 2026

Show code
import sys
from pathlib import Path

project_root = Path().resolve().parent.parent
if str(project_root) not in sys.path:
    sys.path.insert(0, str(project_root))

import warnings
warnings.filterwarnings("ignore")

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import pandas as pd
import numpy as np
from IPython.display import display, HTML, Markdown

ERROR_DIR = project_root / "data" / "analysis" / "error"
ROI_DIR   = project_root / "data" / "analysis" / "roi"

# --- load all CSVs ---
df_err_overall   = pd.read_csv(ERROR_DIR / "roi_simulation.csv")
df_err_region    = pd.read_csv(ERROR_DIR / "segment_regionId.csv")
df_err_elo       = pd.read_csv(ERROR_DIR / "elo_gap_bins.csv")
df_err_season    = pd.read_csv(ERROR_DIR / "season_metrics.csv")

df_roi_overall   = pd.read_csv(ROI_DIR / "roi_simulation.csv")
df_roi_region    = pd.read_csv(ROI_DIR / "roi_by_region.csv")
df_roi_threshold = pd.read_csv(ROI_DIR / "roi_by_threshold.csv")
df_roi_elo       = pd.read_csv(ROI_DIR / "roi_by_elo_bin.csv")

0. Bet365 odds data — load_odds_fdco

load_odds_fdco stage scrapes closing odds from football-data.co.uk and stores them in data/raw/odds_fdco.parquet. This dataset is joined to holdout predictions in the analysis stage to compute ROI benchmarks in sections 4–6 below.

Show code
import yaml
import pandas as pd
from IPython.display import display, HTML, Markdown

with open(project_root / "params.yaml") as _f:
    _params = yaml.safe_load(_f)

_odds = pd.read_parquet(project_root / "data/raw/odds_fdco.parquet")

_leagues = [l["name"] for l in _params["odds_fdco"].get("leagues", [])]
_extra   = [l["name"] for l in _params["odds_fdco"].get("extra_leagues", [])]
_seasons = _params["odds_fdco"].get("seasons", [])

display(Markdown(f"""
| Property | Value |
|---|---|
| Rows | {len(_odds):,} |
| Columns | {_odds.shape[1]} (`season`, `league_code`, `date`, `home_team`, `away_team`, `ftr`, `b365h/d/a`, `vig`, …) |
| Date range | {str(_odds['date'].min())[:10]} → {str(_odds['date'].max())[:10]} |
| Seasons ingested | {', '.join(_seasons)} |
| Top-tier leagues | {len(_leagues)} (Premier League, La Liga, Bundesliga, Serie A, Ligue 1, …) |
| Extra leagues | {len(_extra)} (Norway, Sweden, Brazil, MLS, Japan, …) |
| Total leagues | {_odds['league_code'].nunique()} unique codes present |
"""))
Property Value
Rows 32,579
Columns 14 (season, league_code, date, home_team, away_team, ftr, b365h/d/a, vig, …)
Date range 2023-01-20 → 2026-05-04
Seasons ingested 2526, 2425, 2324
Top-tier leagues 18 (Premier League, La Liga, Bundesliga, Serie A, Ligue 1, …)
Extra leagues 15 (Norway, Sweden, Brazil, MLS, Japan, …)
Total leagues 33 unique codes present

1. Overall model quality (holdout set)

Show code
import yaml
with open(project_root / "params.yaml") as _f:
    PARAMS = yaml.safe_load(_f)

model_name  = PARAMS["inference"]["model_name"]
model_stage = PARAMS["inference"]["model_stage"]

# error_analysis roi_simulation uses uniform payout — shows pure prediction quality
row = df_err_overall.iloc[0]

display(Markdown(f"""
| Metric | Value |
|---|---|
| Model | `{model_name}` @ `{model_stage}` |
| Holdout matches | {int(row.n_matches):,} |
| Accuracy (argmax) | {row.hit_rate:.3f} |
"""))
Metric Value
Model soccer-match-outcome @ champion
Holdout matches 135,970
Accuracy (argmax) 0.504
Show code
# Overall logloss / brier from the full holdout (all regions)
# Use the weighted mean across all regions as proxy
logloss_overall = np.average(df_err_region["logloss"], weights=df_err_region["n"])
brier_overall   = np.average(df_err_region["brier"],   weights=df_err_region["n"])
ece_overall     = np.average(df_err_region["ece"],     weights=df_err_region["n"])

display(Markdown(f"""
| Metric | Value |
|---|---|
| Log-loss (weighted avg) | {logloss_overall:.4f} |
| Brier score (weighted avg) | {brier_overall:.4f} |
| ECE (weighted avg) | {ece_overall:.4f} |
"""))
Metric Value
Log-loss (weighted avg) 1.0057
Brier score (weighted avg) 0.6011
ECE (weighted avg) 0.0267

2. Model quality by region

Regions sorted by logloss (ascending = better calibration). ★ = regions that also have Bet365/Pinnacle odds coverage (ROI benchmark available).

Show code
# Merge error + ROI region data
df_reg = df_err_region.copy()
if "logloss" in df_roi_region.columns:
    df_roi_reg_slim = df_roi_region[["regionId", "n_bets", "roi_pct", "low_logloss"]].copy()
    df_reg = df_reg.merge(df_roi_reg_slim, left_on="id", right_on="regionId", how="left")

logloss_median = df_reg["logloss"].median()

# Top-30 by match count for the chart
df_top = df_reg.nlargest(30, "n").sort_values("logloss")

has_bets   = df_top["n_bets"].notna() if "n_bets" in df_top.columns else pd.Series(False, index=df_top.index)
bar_colors = ["#e67e22" if hb else "#3498db" for hb in has_bets]

fig, ax = plt.subplots(figsize=(10, 8))
ax.barh(df_top["segment"], df_top["logloss"], color=bar_colors)
ax.axvline(logloss_median, color="black", linewidth=0.9, linestyle="--", label=f"Median {logloss_median:.3f}")
ax.set_xlabel("Log-loss")
ax.set_title("Log-loss by region (top-30 by match count)")
ax.invert_yaxis()
legend_elements = [
    mpatches.Patch(facecolor="#e67e22", label="Has odds coverage (★)"),
    mpatches.Patch(facecolor="#3498db", label="No odds data"),
]
ax.legend(handles=legend_elements, fontsize=8)
plt.tight_layout()
plt.show()

Log-loss by region (top-30 by match count)
Show code
# All regions sorted by logloss; join n_bets + roi_pct where available
cols_show = ["segment", "n", "logloss", "brier", "ece"]
df_show = df_reg[cols_show].copy()

if "n_bets" in df_reg.columns:
    df_show["n_bets"] = df_reg["n_bets"].apply(lambda x: int(x) if pd.notna(x) else "—")
    df_show["roi_pct"] = df_reg["roi_pct"].apply(lambda x: f"{x:.2f}%" if pd.notna(x) else "—")
    if "low_logloss" in df_reg.columns:
        df_show["segment"] = df_show["segment"].where(
            ~df_reg["low_logloss"].fillna(False),
            "★ " + df_show["segment"]
        )

df_show = df_show.sort_values("logloss").reset_index(drop=True)
df_show["logloss"] = df_show["logloss"].map("{:.4f}".format)
df_show["brier"]   = df_show["brier"].map("{:.4f}".format)
df_show["ece"]     = df_show["ece"].map("{:.4f}".format)

display(HTML(df_show.to_html(index=False)))
segment n logloss brier ece n_bets roi_pct
Faroe Islands 314 0.7931 0.4531 0.0497 — —
Malaysia 306 0.8616 0.5063 0.0546 — —
Armenia 214 0.8765 0.5130 0.0582 — —
Estonia 415 0.8783 0.5116 0.0479 — —
Bosnia-Herzegovina 450 0.8823 0.5140 0.0410 — —
Latvia 423 0.8879 0.5168 0.0505 — —
Singapore 264 0.8924 0.5189 0.0509 — —
Kuwait 184 0.8978 0.5261 0.0695 — —
Tanzania 556 0.8980 0.5314 0.0521 — —
Saudi Arabia 731 0.9336 0.5525 0.0347 — —
Africa 626 0.9357 0.5514 0.0641 — —
Nigeria 963 0.9377 0.5554 0.1170 — —
N. Ireland 689 0.9389 0.5529 0.0469 — —
Moldova 224 0.9395 0.4585 0.0533 — —
International 4466 0.9417 0.5574 0.0207 — —
★ Norway 4685 0.9442 0.5536 0.0237 314 -8.26%
★ Turkey 2040 0.9568 0.5695 0.0206 666 -11.33%
★ Greece 1463 0.9575 0.5680 0.0273 221 -9.39%
Azerbaijan 457 0.9587 0.5668 0.0386 — —
U.A.E. 453 0.9601 0.5698 0.0403 — —
Asia 603 0.9637 0.5707 0.0355 — —
Peru 798 0.9638 0.5716 0.0458 — —
Cyprus 1266 0.9645 0.5717 0.0367 — —
Tunisia 565 0.9656 0.5781 0.0386 — —
Thailand 599 0.9691 0.5754 0.0479 — —
Bolivia 615 0.9703 0.5755 0.0389 — —
Wales 470 0.9713 0.5729 0.0529 — —
Ghana 744 0.9734 0.5799 0.0835 — —
Croatia 474 0.9735 0.5765 0.0529 — —
Serbia 729 0.9750 0.5795 0.0333 — —
Ukraine 608 0.9757 0.5796 0.0393 — —
Macedonia 480 0.9775 0.5823 0.0319 — —
Slovenia 464 0.9800 0.5821 0.0270 — —
North & Central America 438 0.9814 0.5818 0.0526 — —
Europe 2691 0.9829 0.5851 0.0351 — —
Guatemala 633 0.9845 0.5865 0.0689 — —
Czech Republic 1345 0.9853 0.5879 0.0214 — —
Undefined 580 0.9881 0.5904 0.0615 — —
Mexico 842 0.9906 0.5909 0.0284 — —
South Africa 639 0.9921 0.5942 0.0315 — —
★ Netherlands 2610 0.9922 0.5925 0.0143 371 -11.29%
Morocco 535 0.9935 0.5971 0.0506 — —
★ China 1277 0.9937 0.5937 0.0242 326 -29.25%
Slovakia 1122 0.9944 0.5922 0.0237 — —
★ Finland 1194 0.9953 0.5935 0.0161 148 -24.45%
★ Sweden 2446 0.9963 0.5947 0.0158 213 -5.00%
Bulgaria 1537 0.9971 0.5957 0.0185 — —
★ Scotland 2498 0.9980 0.5950 0.0127 456 -2.83%
Kazakhstan 495 1.0000 0.5971 0.0398 — —
Iraq 713 1.0008 0.5990 0.0316 — —
Algeria 611 1.0038 0.6020 0.0383 — —
Portugal 2526 1.0044 0.6016 0.0139 287 -4.81%
Belarus 560 1.0068 0.6006 0.0305 — —
Belgium 1437 1.0087 0.6023 0.0229 206 -11.03%
Honduras 545 1.0090 0.6050 0.0419 — —
Austria 1174 1.0093 0.6048 0.0247 145 0.47%
Spain 4841 1.0098 0.6045 0.0098 693 -15.73%
Russia 2588 1.0100 0.6043 0.0160 159 -7.34%
France 2799 1.0106 0.6056 0.0203 1011 -9.13%
Israel 1537 1.0128 0.6073 0.0352 — —
Luxembourg 584 1.0161 0.5678 0.0439 — —
Romania 1560 1.0174 0.6083 0.0151 133 -15.50%
Colombia 2017 1.0180 0.6099 0.0265 — —
Egypt 745 1.0181 0.6138 0.0644 — —
Indonesia 704 1.0191 0.6108 0.0248 — —
Germany 6511 1.0204 0.6110 0.0189 585 -12.53%
El Salvador 678 1.0207 0.6102 0.0366 — —
Iceland 692 1.0209 0.6123 0.0258 — —
Switzerland 1099 1.0214 0.6126 0.0249 — —
Qatar 326 1.0246 0.6093 0.0708 — —
England 15106 1.0267 0.6162 0.0173 3573 -5.20%
Vietnam 465 1.0286 0.6176 0.0298 — —
South America 801 1.0291 0.6179 0.0455 — —
Ireland 979 1.0291 0.6204 0.0239 118 -12.49%
Denmark 1956 1.0298 0.6173 0.0191 — —
India 584 1.0328 0.6195 0.0289 — —
Italy 5189 1.0332 0.6217 0.0244 1528 -15.03%
Venezuela 570 1.0333 0.6230 0.0297 — —
USA 3279 1.0349 0.6221 0.0149 648 -18.97%
Brazil 3579 1.0350 0.6222 0.0225 389 -32.21%
Ecuador 659 1.0355 0.6235 0.0306 — —
Iran 1222 1.0369 0.6265 0.0542 — —
Hungary 1151 1.0374 0.6227 0.0185 — —
Georgia 425 1.0383 0.6244 0.0532 — —
New Zealand 102 1.0412 0.6294 0.0901 — —
Japan 2711 1.0468 0.6299 0.0218 415 -11.88%
Uzbekistan 62 1.0494 0.6317 0.0510 — —
Argentina 4677 1.0506 0.6340 0.0196 430 -13.84%
Australia 568 1.0525 0.6347 0.0420 — —
Chile 1201 1.0532 0.6341 0.0263 — —
Montenegro 434 1.0558 0.6353 0.0343 — —
Poland 2261 1.0583 0.6384 0.0232 282 -27.53%
Lithuania 430 1.0602 0.6376 0.0653 — —
Uruguay 1230 1.0615 0.6400 0.0341 — —
South Korea 1756 1.0658 0.6434 0.0359 — —
Albania 457 1.0789 0.6537 0.0440 — —
Paraguay 649 1.0793 0.6532 0.0481 — —

3. Model quality by ELO gap

ELO gap = |home ELO − away ELO| before the match. Hypothesis: wider gap → more predictable → lower logloss.

Show code
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# Left: logloss
axes[0].bar(df_err_elo["elo_gap_bin"], df_err_elo["logloss"], color="#3498db")
axes[0].set_ylabel("Log-loss")
axes[0].set_title("Log-loss by ELO gap bin")
axes[0].tick_params(axis="x", rotation=20)

# Right: ROI
if not df_roi_elo.empty:
    colors = ["#2ecc71" if v >= 0 else "#e74c3c" for v in df_roi_elo["roi_pct"]]
    axes[1].bar(df_roi_elo["elo_gap_bin"], df_roi_elo["roi_pct"], color=colors)
    axes[1].axhline(0, color="black", linewidth=0.8, linestyle="--")
    axes[1].set_ylabel("ROI %")
    axes[1].set_title("ROI by ELO gap bin (matched only)")
    axes[1].tick_params(axis="x", rotation=20)

plt.tight_layout()
plt.show()

Log-loss and ROI by ELO gap bin
Show code
df_elo_joined = df_err_elo[["elo_gap_bin", "n", "logloss", "brier", "ece"]].copy()
if not df_roi_elo.empty:
    df_elo_joined = df_elo_joined.merge(
        df_roi_elo[["elo_gap_bin", "n_bets", "roi_pct"]], on="elo_gap_bin", how="left"
    )
    df_elo_joined["roi_pct"] = df_elo_joined["roi_pct"].map(lambda x: f"{x:.2f}%" if pd.notna(x) else "—")

for col in ["logloss", "brier", "ece"]:
    df_elo_joined[col] = df_elo_joined[col].map("{:.4f}".format)

display(HTML(df_elo_joined.to_html(index=False)))
elo_gap_bin n logloss brier ece n_bets roi_pct
clear (150-300) 25334 0.9010 0.5261 0.0086 2716 -7.98%
moderate (50-150) 58917 1.0323 0.6201 0.0046 5813 -11.02%
even (<50) 47625 1.0606 0.6405 0.0050 4232 -14.73%
large (300+) 4094 0.6324 0.3337 0.0091 556 -8.27%

4. ROI simulation — Bet365 closing odds benchmark

Coverage: rows matched to Bet365/Pinnacle closing odds via team name fuzzy join. Flat-stake simulation: €1 per bet, payout = actual odds. Uniform prior fallback for unmatched rows.

Show code
row = df_roi_overall.iloc[0]
n_matched = int(row.n_bets)
n_total   = int(row.n_matches)
coverage  = n_matched / n_total

display(Markdown(f"""
| Metric | Value |
|---|---|
| Holdout matches | {n_total:,} |
| Matched to odds | {n_matched:,} ({coverage:.1%}) |
| Bets placed | {n_matched:,} |
| Hit rate | {row.hit_rate:.3f} |
| Net profit | {row.net_profit:+.1f} units |
| **ROI** | **{row.roi_pct:.2f}%** |
"""))
Metric Value
Holdout matches 135,970
Matched to odds 13,317 (9.8%)
Bets placed 13,317
Hit rate 0.347
Net profit -1526.9 units
ROI -11.47%

5. ROI by region

Regions with odds coverage only. ★ = logloss below median across all regions.

Show code
df_rr = df_roi_region.copy()
label_col = "region_name" if "region_name" in df_rr.columns else "regionId"
has_ll = "low_logloss" in df_rr.columns

df_plot = df_rr.sort_values("roi_pct", ascending=False).head(25)

bar_colors = []
y_labels   = []
for _, r in df_plot.iterrows():
    name = str(r[label_col])
    if r["roi_pct"] >= 0:
        bar_colors.append("#2ecc71")
    elif has_ll and r.get("low_logloss", False):
        bar_colors.append("#e67e22")
    else:
        bar_colors.append("#e74c3c")
    y_labels.append(("★ " + name) if (has_ll and r.get("low_logloss", False)) else name)

fig, ax = plt.subplots(figsize=(10, 7))
ax.barh(y_labels, df_plot["roi_pct"].tolist(), color=bar_colors)
ax.axvline(0, color="black", linewidth=0.8, linestyle="--")
ax.set_xlabel("ROI %")
ax.invert_yaxis()

if has_ll:
    logloss_thr = df_roi_region.loc[df_roi_region["low_logloss"].notna(), "logloss"].median()
    ax.set_title(f"ROI by region (top-25 by bets)\n★ = logloss < {logloss_thr:.3f} (median)")
    legend_elements = [
        mpatches.Patch(facecolor="#e67e22", label=f"Low logloss (< {logloss_thr:.3f})"),
        mpatches.Patch(facecolor="#e74c3c", label="Other"),
    ]
    ax.legend(handles=legend_elements, loc="lower right", fontsize=8)
else:
    ax.set_title("ROI by region (top-25 by bets)")

plt.tight_layout()
plt.show()

ROI by region (top-25 by bet count, matched rows only)
Show code
df_show = df_rr[[label_col, "n_bets", "hit_rate", "roi_pct"]].copy()
if has_ll:
    df_show["logloss"] = df_rr["logloss"].map(lambda x: f"{x:.4f}" if pd.notna(x) else "—")
    df_show[label_col] = df_show[label_col].where(
        ~df_rr["low_logloss"].fillna(False),
        "★ " + df_show[label_col]
    )

df_show["hit_rate"] = df_show["hit_rate"].map("{:.3f}".format)
df_show["roi_pct"]  = df_show["roi_pct"].map("{:.2f}%".format)
df_show["n_bets"]   = df_show["n_bets"].astype(int)
df_show = df_show.sort_values("roi_pct")

display(HTML(df_show.to_html(index=False)))
region_name n_bets hit_rate roi_pct logloss
Belgium 206 0.359 -11.03% 1.0087
★ Netherlands 371 0.383 -11.29% 0.9922
★ Turkey 666 0.389 -11.33% 0.9568
Japan 415 0.359 -11.88% 1.0468
Ireland 118 0.305 -12.49% 1.0291
Germany 585 0.337 -12.53% 1.0204
Argentina 430 0.302 -13.84% 1.0506
Italy 1528 0.356 -15.03% 1.0332
Romania 133 0.316 -15.50% 1.0174
Spain 693 0.332 -15.73% 1.0098
USA 648 0.296 -18.97% 1.0349
★ Scotland 456 0.395 -2.83% 0.9980
★ Finland 148 0.338 -24.45% 0.9953
Poland 282 0.298 -27.53% 1.0583
★ China 326 0.334 -29.25% 0.9937
Brazil 389 0.265 -32.21% 1.0350
Portugal 287 0.390 -4.81% 1.0044
★ Sweden 213 0.423 -5.00% 0.9963
England 3573 0.343 -5.20% 1.0267
Russia 159 0.415 -7.34% 1.0100
★ Norway 314 0.357 -8.26% 0.9442
France 1011 0.345 -9.13% 1.0106
★ Greece 221 0.335 -9.39% 0.9575
Austria 145 0.455 0.47% 1.0093

6. ROI by minimum edge threshold

Edge = model probability − implied bookmaker probability. Higher threshold → fewer but more confident bets.

Show code
fig, ax = plt.subplots(figsize=(9, 4))
ax.plot(df_roi_threshold["min_edge"], df_roi_threshold["roi_pct"],
        marker="o", color="#3498db")
ax.axhline(0, color="black", linewidth=0.8, linestyle="--")
ax.set_xlabel("Min edge threshold")
ax.set_ylabel("ROI %")
ax.set_title("ROI vs minimum edge threshold (matched only)")

for _, r in df_roi_threshold.iterrows():
    ax.annotate(
        f"n={int(r['n_bets'])}",
        (r["min_edge"], r["roi_pct"]),
        textcoords="offset points",
        xytext=(0, 8),
        ha="center",
        fontsize=8,
    )
plt.tight_layout()
plt.show()

ROI vs minimum edge threshold
Show code
df_t = df_roi_threshold[["min_edge", "n_bets", "bet_rate", "hit_rate", "roi_pct"]].copy()
df_t["roi_pct"]  = df_t["roi_pct"].map("{:.2f}%".format)
df_t["hit_rate"] = df_t["hit_rate"].map("{:.3f}".format)
df_t["bet_rate"] = df_t["bet_rate"].map("{:.3f}".format)
df_t["n_bets"]   = df_t["n_bets"].astype(int)

display(HTML(df_t.to_html(index=False)))
min_edge n_bets bet_rate hit_rate roi_pct
0.00 13317 1.000 0.347 -11.47%
0.02 11089 0.833 0.348 -12.47%
0.05 6506 0.489 0.356 -15.03%
0.10 2194 0.165 0.365 -16.33%
0.15 569 0.043 0.364 -21.97%
0.20 130 0.010 0.377 -26.44%
0.25 35 0.003 0.371 -18.16%

7. Model quality by season

Show code
# Aggregate per year from seasonId (format: e.g. "2023")
df_s = df_err_season.copy()
df_s["year"] = df_s["seasonId"].astype(str).str[:4]
df_by_year = (
    df_s.groupby("year")
    .apply(lambda g: pd.Series({
        "n": g["n"].sum(),
        "logloss": np.average(g["logloss"], weights=g["n"]),
        "brier":   np.average(g["brier"],   weights=g["n"]),
    }))
    .reset_index()
    .sort_values("year")
)

fig, ax = plt.subplots(figsize=(10, 4))
ax.bar(df_by_year["year"], df_by_year["logloss"], color="#3498db")
ax.set_xlabel("Year")
ax.set_ylabel("Log-loss (weighted avg)")
ax.set_title("Log-loss by year (all tournaments, weighted by match count)")
ax.tick_params(axis="x", rotation=45)
plt.tight_layout()
plt.show()

Log-loss by tournament season (top-30 by match count)
Show code
df_by_year["logloss"] = df_by_year["logloss"].map("{:.4f}".format)
df_by_year["brier"]   = df_by_year["brier"].map("{:.4f}".format)
df_by_year["n"]       = df_by_year["n"].astype(int)

display(HTML(df_by_year.to_html(index=False)))
year n logloss brier
1000 2307 1.0137 0.6068
1001 257 1.0256 0.6160
1002 126 0.9089 0.5315
1003 300 0.9448 0.5570
1004 119 0.7532 0.4260
1005 97 0.9039 0.5297
1008 144 0.9476 0.5573
1021 30 1.0279 0.6168
1028 375 0.9887 0.5904
1029 677 0.9771 0.5806
1030 1814 1.0018 0.5972
1031 2114 0.9875 0.5886
1032 1995 1.0027 0.5999
1033 2181 1.0026 0.5978
1034 4353 1.0483 0.6259
1035 1449 1.0248 0.6139
1036 1678 1.0237 0.6139
1037 1715 0.9724 0.5793
1038 917 0.9521 0.5636
1039 3304 1.0201 0.6109
1040 2526 1.0357 0.6234
1041 1629 0.9588 0.5695
1042 3636 1.0317 0.6203
1043 1684 1.0170 0.6102
1044 642 0.9245 0.5471
1045 1217 0.9598 0.5711
1046 185 1.0239 0.6143
1047 502 1.0266 0.6185
1048 706 0.9056 0.5311
1049 676 0.9616 0.5710
1050 831 0.9614 0.5741
1051 192 1.0294 0.6207
1052 765 0.9758 0.5808
1053 846 1.0216 0.6150
1054 102 0.8705 0.5049
1055 1462 0.9867 0.5892
1056 2078 1.0348 0.6217
1057 3548 0.9976 0.5960
1058 1342 1.0590 0.6394
1059 2298 0.9975 0.5957
1060 1219 1.0257 0.6153
1061 1353 0.9497 0.5629
1062 897 1.0007 0.5974
1063 840 1.0171 0.6078
1064 1074 1.0482 0.6312
1065 505 0.9692 0.5762
1066 201 0.7639 0.4343
1067 179 0.7792 0.4440
1068 92 0.8345 0.4827
1071 241 0.9891 0.5877
1072 3076 1.0081 0.6026
1073 1274 1.0287 0.5998
1074 1487 1.0224 0.6126
1075 1576 1.0153 0.6080
1076 1807 1.0161 0.6089
1077 1729 1.0070 0.6023
1078 2892 1.0372 0.6231
1079 1067 0.9797 0.5831
1080 2113 1.0203 0.6112
1081 2316 1.0243 0.6138
1082 1728 0.9939 0.5931
1083 2303 1.0118 0.6062
1084 2474 1.0137 0.6067
1085 1311 0.9633 0.5728
1086 2788 1.0281 0.6183
1087 1220 0.9796 0.5856
1088 1041 0.9403 0.5584
1089 317 0.9110 0.5355
1090 816 0.9577 0.5692
1091 1172 0.9764 0.5820
1092 387 0.8519 0.4963
1093 308 0.9297 0.5478
1094 121 0.9489 0.5621
1095 558 1.0449 0.6294
1096 228 1.0255 0.6155
1097 364 1.0300 0.6172
1098 728 1.0401 0.6267
1099 849 1.0537 0.6361
1100 839 1.0519 0.6333
1101 840 1.0355 0.6205
1102 468 1.0680 0.6453
1103 211 1.0657 0.6420
1104 354 1.0154 0.6096
1105 271 1.0318 0.6188
1106 181 1.0285 0.6179
1107 52 1.0220 0.6125
1108 44 0.7408 0.4104
9299 51 1.0357 0.6240
9452 111 0.9589 0.5702
9459 60 0.9820 0.5896
9595 51 0.9730 0.5766
9608 55 0.9184 0.5367
9618 184 0.9116 0.5334
9621 267 1.0822 0.6553
9622 257 1.0579 0.6341
9623 273 1.0332 0.6179
9630 109 0.9956 0.5916
9635 153 1.0453 0.6327
9639 170 1.0059 0.6044
9647 88 0.8810 0.5084
9649 163 0.9992 0.5960
9650 153 1.0263 0.6100
9652 183 1.0602 0.6386
9653 691 1.0326 0.6189
9655 124 0.9984 0.5931
9656 126 0.9972 0.5951
9657 138 1.0856 0.6579
9658 129 0.9931 0.5947
9659 200 1.0155 0.6139
9660 153 1.0243 0.6083
9661 118 1.0697 0.6458
9662 142 1.0325 0.6197
9663 136 1.1350 0.6924
9665 91 1.0157 0.6088
9666 121 0.9773 0.5808
9668 110 0.9530 0.5634
9670 189 1.0819 0.6541
9671 84 1.0795 0.6563
9672 45 1.1487 0.7066
9673 72 0.9546 0.5756
9674 150 1.0102 0.6065
9676 120 1.0424 0.6251
9677 92 0.9682 0.5752
9678 179 1.0358 0.6209
9680 112 1.0653 0.6410
9682 200 0.9833 0.5870
9684 96 0.9996 0.5947
9685 85 1.0551 0.6382
9687 85 1.0276 0.6136
9690 30 0.8624 0.4931
9693 96 1.0625 0.6418
9696 98 0.9795 0.5866
9701 84 0.9913 0.5873
9702 93 1.0827 0.6617
9703 117 1.0124 0.6096
9704 149 1.0399 0.6237
9705 165 0.9214 0.5452
9706 181 1.0349 0.6214
9707 237 1.0619 0.6422
9708 89 0.9281 0.5451
9709 182 1.0965 0.6663
9710 95 1.1086 0.6743
9711 93 1.0589 0.6335
9712 90 0.9739 0.5756
9713 111 0.9315 0.5440
9715 148 1.0229 0.6114
9716 96 1.0135 0.6052
9717 96 1.0498 0.6302
9725 167 1.0701 0.6461
9728 90 0.8865 0.5191
9730 171 0.9190 0.5450
9731 170 1.0501 0.6319
9732 126 1.0398 0.6257
9733 104 0.9817 0.5847
9734 252 1.0709 0.6490
9735 533 1.0147 0.6071
9738 112 0.9514 0.5641
9741 30 0.8572 0.5097
9748 156 1.0213 0.6138
9749 121 0.9292 0.5493
9750 32 1.0441 0.6229
9752 200 1.0717 0.6474
9753 157 1.0241 0.6129
9755 866 1.0020 0.5982
9756 115 1.0733 0.6531
9757 102 0.9544 0.5684
9758 621 1.0510 0.6343
9759 90 0.9649 0.5679
9762 135 0.9254 0.5480
9764 210 0.9476 0.5641
9765 136 0.9710 0.5741
9769 124 1.0261 0.6181
9772 72 0.7650 0.4345
9773 156 1.0022 0.5975
9774 434 1.0327 0.6212
9775 158 0.9658 0.5754
9778 45 1.0483 0.6359
9780 161 0.9809 0.5833
9782 144 0.8919 0.5220
9787 90 1.0349 0.6281
9793 170 0.8518 0.4993
9794 210 0.8375 0.4860
9795 60 1.1284 0.6834
9798 94 1.0622 0.6378
9800 139 1.0845 0.6569
9805 122 0.9989 0.5965
9806 134 0.9173 0.5457
9807 92 1.0293 0.6209
9809 145 1.0396 0.6248
9811 130 0.8147 0.4719
9815 31 0.9234 0.5462
9816 137 0.9799 0.5855
9822 139 0.9853 0.5910
9825 110 1.0464 0.6299
9827 157 0.9748 0.5821
9829 76 0.9745 0.5768
9832 225 0.8952 0.5243
9834 31 0.7169 0.4008
9837 71 0.9549 0.5600
9845 144 0.8689 0.5071
9847 72 0.7853 0.4500
9848 72 0.9382 0.5514
9849 75 0.8686 0.5037
9850 221 0.9895 0.5923
9851 223 0.9825 0.5878
9856 126 1.0334 0.6214
9862 33 0.8622 0.5043
9864 33 0.8440 0.4932
9866 30 0.9796 0.5865
9867 83 1.0023 0.5991
9868 45 0.9118 0.5374
9869 52 1.0975 0.6730
9871 63 0.8641 0.5003
9882 255 0.9442 0.5596
9890 84 1.0841 0.6550
9896 139 1.0090 0.6046
9898 955 0.9812 0.5843
9909 264 1.0788 0.6525
9910 32 0.8903 0.5252
9911 31 0.7451 0.4203
9917 51 0.9155 0.5321
9918 180 1.0790 0.6559
9919 185 1.0431 0.6324
9921 240 1.0444 0.6291
9922 423 1.0458 0.6299
9923 124 0.9729 0.5809
9924 141 1.0287 0.6123
9925 240 1.0286 0.6172
9926 240 1.0427 0.6288
9927 522 1.0597 0.6392
9928 240 1.0679 0.6459
9929 435 1.0409 0.6266
9930 310 0.9858 0.5851
9931 380 1.0926 0.6620
9932 383 1.0331 0.6190
9933 380 1.0504 0.6330
9934 162 0.9827 0.5849
9935 137 1.0672 0.6428
9936 364 0.9677 0.5749
9937 63 1.0308 0.6185
9939 1091 0.8939 0.5219
9940 378 1.0672 0.6457
9941 203 1.0781 0.6525
9942 49 1.0299 0.6146
9945 1004 1.0315 0.6204
9949 306 0.9182 0.5418
9950 234 1.0586 0.6392
9951 480 1.0305 0.6170
9953 240 1.0411 0.6246
9955 167 1.0247 0.6148
9957 228 1.0813 0.6554
9958 236 1.1182 0.6807
9959 180 0.9087 0.5353
9961 180 1.0549 0.6386
9964 242 0.9991 0.5962
9965 135 0.6913 0.3822
9966 70 1.0692 0.6501
9967 252 1.0956 0.6661
9968 189 0.9689 0.5744
9969 100 0.9062 0.5270
9972 70 1.0071 0.6021
9973 122 0.9627 0.5680
9974 319 1.0005 0.5961
9976 297 1.0247 0.6123
9977 127 0.9587 0.3976
9980 60 1.0062 0.6024
9981 48 0.9726 0.5776
9982 48 0.9332 0.5492
9984 240 0.9376 0.5522
9985 135 1.0416 0.6265
9987 180 1.0904 0.6565
9989 240 1.0527 0.6336
9990 182 0.8642 0.5046
9991 162 1.0061 0.6028
9995 77 1.0911 0.6615
9996 156 0.9949 0.5935
9997 45 0.9762 0.5777
9999 240 1.0234 0.6137