{"id":3294,"date":"2026-01-01T07:00:01","date_gmt":"2026-01-01T13:00:01","guid":{"rendered":"https:\/\/wollen.org\/blog\/?p=3294"},"modified":"2026-02-21T00:20:58","modified_gmt":"2026-02-21T06:20:58","slug":"scottie-scheffler","status":"publish","type":"post","link":"https:\/\/wollen.org\/blog\/2026\/01\/scottie-scheffler\/","title":{"rendered":"Is Scottie Scheffler the new Tiger Woods?"},"content":{"rendered":"<p>Scottie Scheffler has been <a href=\"https:\/\/www.pgatour.com\/stats\/detail\/186\" target=\"_blank\" rel=\"noopener\">ranked #1<\/a> on the PGA Tour for over three years now. In 2025 he won six tournaments, including two major championships. At this point hardly anyone disputes that Scheffler is the best golfer in the world. But how do his results compare to other great runs of the past 25 years?<\/p>\n<p>On the PGA Tour players get to choose which tournaments they enter. Most aren&#8217;t present at every event. What we can do is calculate a <em>rolling win rate<\/em> and see how often each player won the tournaments they entered. For example, if someone entered 10 tournaments during a given time frame\u2014we&#8217;ll say two years\u2014and won four of them, that would represent a 40% win rate. We&#8217;ll calculate this rolling win rate for all golfers on tour and see how Scottie compares.<\/p>\n<hr \/>\n<h4>1. The data.<\/h4>\n<p>Grab <a href=\"https:\/\/www.kaggle.com\/datasets\/cviaxmiwnptr\/pga-tour-results-2001-to-may-2024\" target=\"_blank\" rel=\"noopener\">this PGA results dataset<\/a> from Kaggle. It goes back to 2001 so it misses Tiger Woods&#8217; late-90s heyday, but he was still on top of the world until 2010 or so. Tiger will provide a good baseline. The dataset also excludes tournaments with alternate scoring formats. Most of those are team events like the Ryder Cup that I would want to drop anyway, so that&#8217;s fine.<\/p>\n<p>Start by creating a Matplotlib Axes instance for plotting. I&#8217;ll use a custom mplstyle that will be linked at the bottom of this post.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pandas as pd\r\nimport matplotlib.pyplot as plt\r\n\r\nplt.style.use(\"wollen_pga.mplstyle\")\r\n\r\nfig, ax = plt.subplots()<\/pre>\n<p>Load the dataset into a pandas DataFrame. Set the index as the tournament start date column so pandas&#8217; <code>rolling<\/code> method will know where to look.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df_all = pd.read_csv(\"pga_results_2001-2025.tsv\",\r\n                     delimiter=\"\\t\",\r\n                     parse_dates=[\"start\"],\r\n                     index_col=\"start\")<\/pre>\n<p>Create a boolean <em>win<\/em> column. In pandas, calling <code>mean()<\/code> on a Series of bools returns the percentage of TRUE values. We&#8217;ll filter the DataFrame down to each player&#8217;s results and use this column to see how often they won.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">df_all['win'] = df_all['position'] == \"1\"<\/pre>\n<p>By channeling TV cooking show magic I can tell you ahead of time that the winningest golfers during this period were Tiger Woods, Vijay Singh, and Scottie Scheffler. They all produced rolling win rates exceeding 20%. We&#8217;ll iterate through these three names, calculate their win rates, and plot their careers one after another.<\/p>\n<p>For each view of the DataFrame, create a <em>win_rate<\/em> column using the <code>rolling<\/code> method. We specify the window to be 730 days, i.e. two years, and require a minimum of 20 tournaments inside the window to generate a value. Since it&#8217;s operating on a bool column, <code>mean<\/code> tells us how many values are TRUE. Multiply by 100 to convert to a percentage.<\/p>\n<p>Then plot this <em>win_rate<\/em> column on the Axes. Recall that the DataFrame&#8217;s index is tournament start date. We&#8217;re plotting a time series.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">for name in [\"Tiger Woods\", \"Vijay Singh\", \"Scottie Scheffler\"]:\r\n    df = df_all.copy()\r\n\r\n    df = df[df['name'] == name]\r\n\r\n    df['win_rate'] = df['win'].rolling(\"730D\", min_periods=20).mean() * 100\r\n\r\n    ax.plot(df.index, df['win_rate'], label=name)<\/pre>\n<p>Make y-ticks a list of percentage values.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">y_ticks = range(0, 70, 10)\r\nax.set(yticks=y_ticks,\r\n       yticklabels=[f\"{tick}%\" for tick in y_ticks],\r\n       ylim=(-1, y_ticks[-1] * 1.005))<\/pre>\n<p>Pandas&#8217; <code>date_range<\/code> is a convenient way to get a list of evenly spaced timestamps. A frequency of &#8220;2YS&#8221; requests one value every two years (<em>Y<\/em>) at the start (<em>S<\/em>) of the year, i.e. January 1st. These will be our x-ticks.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">x_ticks = pd.date_range(start=\"January 1 2002\", end=\"January 1 2026\", freq=\"2YS\")\r\nx_tick_range = (x_ticks[-1] - x_ticks[0]).days\r\nx_margin = pd.Timedelta(f\"{x_tick_range * 0.02} days\")\r\nx_left, x_right = x_ticks[0] - x_margin, x_ticks[-1] + x_margin\r\nax.set(xticks=x_ticks,\r\n       xticklabels=[tick.strftime(\"%Y\") for tick in x_ticks],\r\n       xlim=(x_left, x_right))<\/pre>\n<p>When a plot requires more than a few words of explanation, I find it&#8217;s best to use a title plus a subtitle. Draw these in the upper-left corner with <code>text<\/code>, which allows for different fonts between the main heading and its subtitle. A <code>weight<\/code> of 400 will be slightly bolder than default.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ax.text(x=x_left + pd.Timedelta(f\"{x_tick_range * 0.01} days\"),\r\n        y=y_ticks[-1] * 1.045,\r\n        s=\"PGA Tour  \u2022  Win Rate During Previous 2 Years\",\r\n        weight=400)\r\n\r\nax.text(x=x_left + pd.Timedelta(f\"{x_tick_range * 0.01} days\"),\r\n        y=y_ticks[-1] * 1.015,\r\n        s=\"Minimum 20 Tournaments in Window  \u2022  Max Win Rate &gt; 20%  \u2022  Data: ESPN\")<\/pre>\n<p>Finally, add a legend in the upper-right corner and save the Figure.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">ax.legend(loc=\"upper right\")\r\n\r\nplt.savefig(\"pga_win_rate.png\", dpi=200)<\/pre>\n<hr \/>\n<h4>2. The output.<\/h4>\n<p><a href=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-scaled.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-3303\" src=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-scaled.png\" alt=\"\" width=\"2560\" height=\"1378\" srcset=\"https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-scaled.png 2560w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-300x162.png 300w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-1024x551.png 1024w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-768x414.png 768w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-1536x827.png 1536w, https:\/\/wollen.org\/blog\/wp-content\/uploads\/2026\/01\/pga_win_rate-2048x1103.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/a><\/p>\n<p>As you can see, Scottie Scheffler isn&#8217;t Tiger Woods <em>yet<\/em>. But his win rate is closer than anyone has gotten since Tiger&#8217;s prime\u2014and it continues to trend upward. Scottie&#8217;s reputation is well deserved.<\/p>\n<p>It&#8217;s worth remembering that the sport has evolved quite a bit in the past 25 years. We calculated how often each player beat their competition, but the competition has grown stronger over time. Tiger recognized it <a href=\"https:\/\/www.nbcsports.com\/golf\/news\/article-golftalkcentral-tiger-deeper-fields-now-there-have-ever-been\" target=\"_blank\" rel=\"noopener\">way back in 2013<\/a>:<\/p>\n<blockquote><p>I think it\u2019s deeper now than it ever has been. There is more young talent. There are more guys winning golf tournaments for the first time. But if you look at the major championships, how long did we go from basically Phil winning [to] Phil winning? I mean, how many first time winners did we have during that stretch? It\u2019s deeper. It\u2019s more difficult to win events now, and it\u2019s only going to get that way.<\/p><\/blockquote>\n<p>Obviously much of that growth can be attributed to Tiger himself. He inspired a whole generation of young golfers.<\/p>\n<p>Today it&#8217;s significantly harder for any one person to rise above the field like Tiger did. I believe there&#8217;s a very real gap between Scheffler and Woods, but expecting anyone to reach those same heights may be unrealistic.<\/p>\n<p>Putting aside the comparisons, we can confidently say that Scheffler is doing something no one else has done in 15 years. It&#8217;s worth taking a moment to appreciate it.<!-- HFCM by 99 Robots - Snippet # 15: endmark-python -->\n<span class=\"endmark-python\"><\/span>\n<!-- \/end HFCM by 99 Robots -->\n<\/p>\n<hr \/>\n<p><a href=\"https:\/\/wollen.org\/misc\/scheffler_2026.zip\"><strong>Download the data.<\/strong><\/a><\/p>\n<p><strong>Full code:<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import pandas as pd\r\nimport matplotlib.pyplot as plt\r\n\r\n\r\nplt.style.use(\"wollen_pga.mplstyle\")\r\n\r\nfig, ax = plt.subplots()\r\n\r\ndf_all = pd.read_csv(\"pga_results_2001-2025.tsv\",\r\n                     delimiter=\"\\t\",\r\n                     parse_dates=[\"start\"],\r\n                     index_col=\"start\")\r\n\r\ndf_all['win'] = df_all['position'] == \"1\"\r\n\r\nfor name in [\"Tiger Woods\", \"Vijay Singh\", \"Scottie Scheffler\"]:\r\n    df = df_all.copy()\r\n\r\n    df = df[df['name'] == name]\r\n\r\n    df['win_rate'] = df['win'].rolling(\"730D\", min_periods=20).mean() * 100\r\n\r\n    ax.plot(df.index, df['win_rate'], label=name)\r\n\r\ny_ticks = range(0, 70, 10)\r\nax.set(yticks=y_ticks,\r\n       yticklabels=[f\"{tick}%\" for tick in y_ticks],\r\n       ylim=(-1, y_ticks[-1] * 1.005))\r\n\r\nx_ticks = pd.date_range(start=\"January 1 2002\", end=\"January 1 2026\", freq=\"2YS\")\r\nx_tick_range = (x_ticks[-1] - x_ticks[0]).days\r\nx_margin = pd.Timedelta(f\"{x_tick_range * 0.02} days\")\r\nx_left, x_right = x_ticks[0] - x_margin, x_ticks[-1] + x_margin\r\nax.set(xticks=x_ticks,\r\n       xticklabels=[tick.strftime(\"%Y\") for tick in x_ticks],\r\n       xlim=(x_left, x_right))\r\n\r\nax.text(x=x_left + pd.Timedelta(f\"{x_tick_range * 0.01} days\"),\r\n        y=y_ticks[-1] * 1.045,\r\n        s=\"PGA Tour  \u2022  Win Rate During Previous 2 Years\",\r\n        weight=400)\r\n\r\nax.text(x=x_left + pd.Timedelta(f\"{x_tick_range * 0.01} days\"),\r\n        y=y_ticks[-1] * 1.015,\r\n        s=\"Minimum 20 Tournaments in Window  \u2022  Max Win Rate &gt; 20%  \u2022  Data: ESPN\")\r\n\r\nax.legend(loc=\"upper right\")\r\n\r\nplt.savefig(\"pga_win_rate.png\", dpi=200)<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Scottie Scheffler has been ranked #1 on the PGA Tour for over three years now. In 2025 he won six tournaments, including two major championships. At this point hardly anyone disputes that Scheffler is the best golfer in the world.<\/p>\n","protected":false},"author":1,"featured_media":3328,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[59],"tags":[661,22,334,122,654,123,662,24,126,30,652,653,46,25,266,655,657,656,660,659,651,663,658],"class_list":["post-3294","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sports","tag-comparison","tag-data","tag-dataframe","tag-dataset","tag-golf","tag-kaggle","tag-majors","tag-matplotlib","tag-mplstyle","tag-pandas","tag-percentage","tag-pga","tag-plot","tag-python","tag-rolling","tag-scheffler","tag-scottie-scheffler","tag-tiger-woods","tag-vijay","tag-vijay-singh","tag-win-rate","tag-wins","tag-woods"],"_links":{"self":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3294","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/comments?post=3294"}],"version-history":[{"count":25,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3294\/revisions"}],"predecessor-version":[{"id":3374,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/posts\/3294\/revisions\/3374"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/media\/3328"}],"wp:attachment":[{"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/media?parent=3294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/categories?post=3294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wollen.org\/blog\/wp-json\/wp\/v2\/tags?post=3294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}