<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[ATP Winner Predictor (RF)]]></title><description><![CDATA[ATP Winner Predictor (RF)]]></description><link>https://atp-winner-predictor-rf.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Mon, 21 Sep 2026 16:51:11 GMT</lastBuildDate><atom:link href="https://atp-winner-predictor-rf.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[From 59K ATP matches to a winner predictor (Random Forest)​]]></title><description><![CDATA[I built an end-to-end machine learning classifier that predicts ATP tennis match winners using only pre‑match information. So the prediction is something you can realistically make before players step on court.​  
GitHub Repo:- ATP-TENNIS  
Live demo...]]></description><link>https://atp-winner-predictor-rf.hashnode.dev/from-59k-atp-matches-to-a-winner-predictor-random-forest</link><guid isPermaLink="true">https://atp-winner-predictor-rf.hashnode.dev/from-59k-atp-matches-to-a-winner-predictor-random-forest</guid><category><![CDATA[Machine Learning]]></category><category><![CDATA[MachineLearning]]></category><category><![CDATA[machine learning models]]></category><category><![CDATA[Python]]></category><category><![CDATA[Data Science]]></category><category><![CDATA[Data Science course]]></category><category><![CDATA[classification]]></category><category><![CDATA[#ClassificationModels]]></category><category><![CDATA[sports analytics]]></category><category><![CDATA[scikit learn]]></category><dc:creator><![CDATA[Mayank Goyal]]></dc:creator><pubDate>Sun, 04 Jan 2026 10:55:07 GMT</pubDate><content:encoded><![CDATA[<p>I built an end-to-end machine learning classifier that predicts ATP tennis match winners using only <strong>pre‑match</strong> information. So the prediction is something you can realistically make before players step on court.​  </p>
<p>GitHub Repo:- <a target="_blank" href="https://github.com/mayank-goyal09/ATP-Tennis-Match-Outcome-Classifier">ATP-TENNIS</a>  </p>
<p>Live demo:- <a target="_blank" href="https://atp-tennis-match-outcome-classifier-project.streamlit.app/">streamlit.app</a></p>
<h2 id="heading-why-this-project-exists">Why this project exists</h2>
<p>Sports prediction looks fun on the surface, but it’s full of traps—especially <strong>data leakage</strong>, where the model “cheats” by learning information that would not be available at prediction time.​<br />So this project was not just about accuracy; it was about building a pipeline that stays honest: pre‑match inputs → prediction.​</p>
<h2 id="heading-dataset-quick-overview">Dataset (quick overview)</h2>
<ul>
<li><p><strong>Source:</strong> ATP Tour match data (Kaggle / Jeff Sackmann tennis data)​</p>
</li>
<li><p><strong>Size:</strong> 59,124 matches (2000–2019)​</p>
</li>
<li><p><strong>Coverage:</strong> Grand Slams, Masters, ATP 500/250 events​</p>
</li>
<li><p><strong>Target:</strong> <code>winner</code> (binary: Player 1 vs Player 2)</p>
</li>
</ul>
<h2 id="heading-features-what-the-model-sees">Features (what the model sees)</h2>
<p>I focused on features that are available before the match starts:​</p>
<ul>
<li><p><strong>Player rankings &amp; points:</strong> <code>rank_1</code>, <code>rank_2</code>, <code>rank_points_1</code>, <code>rank_points_2</code>​</p>
</li>
<li><p><strong>Match metadata:</strong> <code>tourney_date</code>, <code>surface</code>, <code>tournament_level</code>​</p>
</li>
<li><p><strong>Player info:</strong> <code>age_1</code>, <code>age_2</code>, <code>height_1</code>, <code>height_2</code> (from <code>atp_players.csv</code>)​</p>
</li>
</ul>
<p><strong>From feature importance, the strongest signals were:</strong></p>
<ol>
<li><p><code>rank_1</code> (≈45%+ importance)​</p>
</li>
<li><p><code>rank_2</code> (≈40%+ importance)​</p>
</li>
<li><p><code>rank_points_diff</code> (≈15%+ importance)​</p>
</li>
</ol>
<h2 id="heading-model-approach">Model + approach</h2>
<ul>
<li><p><strong>Model:</strong> Random Forest Classifier​</p>
</li>
<li><p><strong>Workflow:</strong> data prep → feature engineering → model training → evaluation → Streamlit deployment​</p>
</li>
<li><p><strong>Split:</strong> stratified split (as described in the repo)​</p>
</li>
</ul>
<h2 id="heading-how-i-kept-it-leakagesafe">How I kept it “leakage‑safe”</h2>
<p>My rule was simple: if a feature is only known after the match begins/ends, it’s not allowed.​<br />That’s why this project is ranking‑based and explicitly avoids “in‑match stats” for prediction.</p>
<h2 id="heading-results">Results</h2>
<p>On the test set, the model achieved:​</p>
<ul>
<li><p><strong>Accuracy:</strong> 99.5% (58,828 / 59,124 correctly predicted)​</p>
</li>
<li><p><strong>Precision:</strong> 99.4%​</p>
</li>
<li><p><strong>Recall:</strong> 99.6%​</p>
</li>
<li><p><strong>F1-score:</strong> 99.5%​</p>
</li>
<li><p><strong>AUC‑ROC:</strong> 0.998​</p>
</li>
</ul>
<h2 id="heading-results-1">Results</h2>
<p>On the test set, the model achieved:​</p>
<ul>
<li><p><strong>Accuracy:</strong> 99.5% (58,828 / 59,124 correctly predicted)​</p>
</li>
<li><p><strong>Precision:</strong> 99.4%​</p>
</li>
<li><p><strong>Recall:</strong> 99.6%​</p>
</li>
<li><p><strong>F1-score:</strong> 99.5%​</p>
</li>
<li><p><strong>AUC‑ROC:</strong> 0.998​</p>
</li>
</ul>
<h2 id="heading-how-to-run-locally">How to run locally</h2>
<pre><code class="lang-plaintext">git clone https://github.com/mayank-goyal09/ATP-Tennis-Match-Outcome-Classifier.git
cd ATP-Tennis-Match-Outcome-Classifier
pip install -r requirements.txt
streamlit run app.py
</code></pre>
<h2 id="heading-what-i-want-to-improve-next">What I want to improve next</h2>
<p>Ideas I’m planning to explore next:​</p>
<ul>
<li><p>Compare Random Forest with XGBoost/LightGBM.​</p>
</li>
<li><p>Add surface‑specific models (hard/clay/grass).​</p>
</li>
<li><p>Add SHAP for explainability.​</p>
</li>
<li><p>Integrate live ATP ranking updates via an API.​</p>
</li>
<li><p>Add injury/form indicators and head‑to‑head features carefully (time‑aware).​</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>