Repository: probberechts/soccerdata (language: python)

Issue:
Incorporating Understat as a Data Source
[Understat](https://understat.com/) exposes data, current and historical, without any apparent restrictions on usage (i.e lacking a robots.txt) on the big 5. It has detailed data on both the player and club level, and even an [unofficial API](https://github.com/amosbastian/understat) that could perhaps be integrated as a data source.


Discussion / hints:
Are there any stats you could get from understat that you couldn't get from FBref (besides the difference in the xG model used)?
> Are there any stats you could get from understat that you couldn't get from FBref (besides the difference in the xG model used)?

I believe xGChain and xGBuildup, for players at least. Although I think those could be calculated from the stats FBref exposes. 

There are a few more alternative stats for teams, such as a team's tempo (what is Dortmund's xG on a slow attack as opposed to their xG for a fast attack) and shot zones.

Understat is also much faster to scrape and allows users to scrape between arbitrary dates, avoiding unnecessary scraping.

Fix patch:
diff --git a/.github/workflows/constraints.txt b/.github/workflows/constraints.txt
index f28989f5..e33b5540 100644
--- a/.github/workflows/constraints.txt
+++ b/.github/workflows/constraints.txt
@@ -1,4 +1,4 @@
-pip==23.3.2
+pip==24.0
 nox==2023.4.22
 nox-poetry==1.0.3
 poetry==1.7.1
diff --git a/README.rst b/README.rst
index 45f50981..a0fe9ae6 100644
--- a/README.rst
+++ b/README.rst
@@ -39,9 +39,9 @@
 
 SoccerData is a collection of scrapers to gather soccer data from popular
 websites, including `Club Elo`_, `ESPN`_, `FBref`_, `FiveThirtyEight`_,
-`Football-Data.co.uk`_, `FotMob`_, `SoFIFA`_ and `WhoScored`_. You get Pandas
-DataFrames with sensible, matching column names and identifiers across
-datasets. Data is downloaded when needed and cached locally.
+`Football-Data.co.uk`_, `FotMob`_, `SoFIFA`_, `Understat`_ and `WhoScored`_.
+You get Pandas DataFrames with sensible, matching column names and identifiers
+across datasets. Data is downloaded when needed and cached locally.
 
 .. code:: python
 
@@ -67,6 +67,7 @@ and `API reference <https://soccerdata.readthedocs.io/en/latest/reference/>`__.
 .. _Football-Data.co.uk: https://www.football-data.co.uk/
 .. _FotMob: https://fotmob.com/
 .. _SoFIFA: https://sofifa.com/
+.. _Understat: https://understat.com/
 .. _WhoScored: https://www.whoscored.com/
 
 **Usage Notice:** Please use this web scraping tool responsibly and in compliance with the terms of service of the
diff --git a/docs/conf.py b/docs/conf.py
index 6775b383..07e465d8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -54,6 +54,7 @@
     'examples/datasources/FiveThirtyEight': '_static/FiveThirtyEight-logo.png',
     'examples/datasources/MatchHistory': '_static/FootballData-logo.jpg',
     'examples/datasources/SoFIFA': '_static/SoFIFA-logo.png',
+    'examples/datasources/Understat': '_static/Understat-logo.png',
 }
 
 # This is processed by Jinja2 and inserted before each notebook
diff --git a/docs/datasources/Understat.ipynb b/docs/datasources/Understat.ipynb
new file mode 100644
index 00000000..cb72da5a
--- /dev/null
+++ b/docs/datasources/Understat.ipynb
@@ -0,0 +1,1926 @@
+{
+    "cells": [
+        {
+            "cell_type": "code",
+            "execution_count": 1,
+            "id": "f5e5541b",
+            "metadata": {
+                "nbsphinx": "hidden",
+                "tags": []
+            },
+            "outputs": [
+                {
+                    "name": "stdout",
+                    "output_type": "stream",
+                    "text": [
+                        "env: SOCCERDATA_LOGLEVEL=ERROR\n",
+                        "env: SOCCERDATA_NOCACHE=False\n",
+                        "env: SOCCERDATA_NOSTORE=False\n"
+                    ]
+                }
+            ],
+            "source": [
+                "%env SOCCERDATA_LOGLEVEL=ERROR\n",
+                "%env SOCCERDATA_NOCACHE=False\n",
+                "%env SOCCERDATA_NOSTORE=False"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 2,
+            "id": "2454afe6",
+            "metadata": {
+                "tags": []
+            },
+            "outputs": [],
+            "source": [
+                "import soccerdata as sd"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "b5784f2d",
+            "metadata": {},
+            "source": [
+                "# Understat"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 3,
+            "id": "8dab5be9",
+            "metadata": {
+                "tags": []
+            },
+            "outputs": [
+                {
+                    "name": "stdout",
+                    "output_type": "stream",
+                    "text": [
+                        "Provides pd.DataFrames from data at https://understat.com.\n",
+                        "\n",
+                        "    Data will be downloaded as necessary and cached locally in\n",
+                        "    ``~/soccerdata/data/Understat``.\n",
+                        "\n",
+                        "    Parameters\n",
+                        "    ----------\n",
+                        "    proxy : 'tor' or dict or list(dict) or callable, optional\n",
+                        "        Use a proxy to hide your IP address. Valid options are:\n",
+                        "            - \"tor\": Uses the Tor network. Tor should be running in\n",
+                        "              the background on port 9050.\n",
+                        "            - dict: A dictionary with the proxy to use. The dict should be\n",
+                        "              a mapping of supported protocols to proxy addresses. For example::\n",
+                        "\n",
+                        "                  {\n",
+                        "                      'http': 'http://10.10.1.10:3128',\n",
+                        "                      'https': 'http://10.10.1.10:1080',\n",
+                        "                  }\n",
+                        "\n",
+                        "            - list(dict): A list of proxies to choose from. A different proxy will\n",
+                        "              be selected from this list after failed requests, allowing rotating\n",
+                        "              proxies.\n",
+                        "            - callable: A function that returns a valid proxy. This function will\n",
+                        "              be called after failed requests, allowing rotating proxies.\n",
+                        "    no_cache : bool\n",
+                        "        If True, will not use cached data.\n",
+                        "    no_store : bool\n",
+                        "        If True, will not store downloaded data.\n",
+                        "    data_dir : Path\n",
+                        "        Path to directory where data will be cached.\n",
+                        "    \n"
+                    ]
+                }
+            ],
+            "source": [
+                "understat = sd.Understat(leagues=\"ENG-Premier League\", seasons=\"2015/2016\")\n",
+                "print(understat.__doc__)"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "f791f100",
+            "metadata": {},
+            "source": [
+                "## Leagues"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 4,
+            "id": "4dc08db7",
+            "metadata": {
+                "tags": []
+            },
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>url</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th>ENG-Premier League</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>https://understat.com/league/EPL</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                   league_id                               url\n",
+                            "league                                                        \n",
+                            "ENG-Premier League         1  https://understat.com/league/EPL"
+                        ]
+                    },
+                    "execution_count": 4,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "leagues = understat.read_leagues()\n",
+                "leagues.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "98881255-a906-4f4f-aeaa-788a46b9fcc1",
+            "metadata": {},
+            "source": [
+                "## Seasons"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 5,
+            "id": "168c34f5-3035-410f-bc74-51c4af9ca4d7",
+            "metadata": {
+                "tags": []
+            },
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>url</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th>ENG-Premier League</th>\n",
+                            "      <th>1516</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>https://understat.com/league/EPL/2015</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                          league_id  season_id  \\\n",
+                            "league             season                        \n",
+                            "ENG-Premier League 1516           1       2015   \n",
+                            "\n",
+                            "                                                             url  \n",
+                            "league             season                                         \n",
+                            "ENG-Premier League 1516    https://understat.com/league/EPL/2015  "
+                        ]
+                    },
+                    "execution_count": 5,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "seasons = understat.read_seasons()\n",
+                "seasons.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "eb5fabf3",
+            "metadata": {},
+            "source": [
+                "## Schedule"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 6,
+            "id": "66ce10da",
+            "metadata": {
+                "tags": []
+            },
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>game_id</th>\n",
+                            "      <th>date</th>\n",
+                            "      <th>home_team_id</th>\n",
+                            "      <th>away_team_id</th>\n",
+                            "      <th>home_team</th>\n",
+                            "      <th>away_team</th>\n",
+                            "      <th>away_team_code</th>\n",
+                            "      <th>home_team_code</th>\n",
+                            "      <th>home_goals</th>\n",
+                            "      <th>away_goals</th>\n",
+                            "      <th>home_xg</th>\n",
+                            "      <th>away_xg</th>\n",
+                            "      <th>is_result</th>\n",
+                            "      <th>has_data</th>\n",
+                            "      <th>url</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th>game</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">ENG-Premier League</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">1516</th>\n",
+                            "      <th>2015-08-08 Bournemouth-Aston Villa</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>73</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>Bournemouth</td>\n",
+                            "      <td>Aston Villa</td>\n",
+                            "      <td>AVL</td>\n",
+                            "      <td>BOU</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0.876106</td>\n",
+                            "      <td>0.782253</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>https://understat.com/match/82</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Chelsea-Swansea</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>86</td>\n",
+                            "      <td>2015-08-08 20:30:00</td>\n",
+                            "      <td>80</td>\n",
+                            "      <td>84</td>\n",
+                            "      <td>Chelsea</td>\n",
+                            "      <td>Swansea</td>\n",
+                            "      <td>SWA</td>\n",
+                            "      <td>CHE</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0.64396</td>\n",
+                            "      <td>2.59203</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>https://understat.com/match/86</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Everton-Watford</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>83</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>72</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>Everton</td>\n",
+                            "      <td>Watford</td>\n",
+                            "      <td>WAT</td>\n",
+                            "      <td>EVE</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0.604226</td>\n",
+                            "      <td>0.557892</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>https://understat.com/match/83</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Leicester-Sunderland</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>84</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>75</td>\n",
+                            "      <td>77</td>\n",
+                            "      <td>Leicester</td>\n",
+                            "      <td>Sunderland</td>\n",
+                            "      <td>SUN</td>\n",
+                            "      <td>LEI</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>2.56803</td>\n",
+                            "      <td>1.45946</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>https://understat.com/match/84</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Manchester United-Tottenham</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>81</td>\n",
+                            "      <td>2015-08-08 15:45:00</td>\n",
+                            "      <td>89</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>Manchester United</td>\n",
+                            "      <td>Tottenham</td>\n",
+                            "      <td>TOT</td>\n",
+                            "      <td>MUN</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.627539</td>\n",
+                            "      <td>0.6746</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>True</td>\n",
+                            "      <td>https://understat.com/match/81</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                                                                 league_id  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa             1   \n",
+                            "                          2015-08-08 Chelsea-Swansea                     1   \n",
+                            "                          2015-08-08 Everton-Watford                     1   \n",
+                            "                          2015-08-08 Leicester-Sunderland                1   \n",
+                            "                          2015-08-08 Manchester United-Tottenham         1   \n",
+                            "\n",
+                            "                                                                  season_id  \\\n",
+                            "league             season game                                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa           2015   \n",
+                            "                          2015-08-08 Chelsea-Swansea                   2015   \n",
+                            "                          2015-08-08 Everton-Watford                   2015   \n",
+                            "                          2015-08-08 Leicester-Sunderland              2015   \n",
+                            "                          2015-08-08 Manchester United-Tottenham       2015   \n",
+                            "\n",
+                            "                                                                  game_id  \\\n",
+                            "league             season game                                              \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa           82   \n",
+                            "                          2015-08-08 Chelsea-Swansea                   86   \n",
+                            "                          2015-08-08 Everton-Watford                   83   \n",
+                            "                          2015-08-08 Leicester-Sunderland              84   \n",
+                            "                          2015-08-08 Manchester United-Tottenham       81   \n",
+                            "\n",
+                            "                                                                                date  \\\n",
+                            "league             season game                                                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa     2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Chelsea-Swansea             2015-08-08 20:30:00   \n",
+                            "                          2015-08-08 Everton-Watford             2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Leicester-Sunderland        2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Manchester United-Tottenham 2015-08-08 15:45:00   \n",
+                            "\n",
+                            "                                                                  home_team_id  \\\n",
+                            "league             season game                                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                73   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        80   \n",
+                            "                          2015-08-08 Everton-Watford                        72   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   75   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            89   \n",
+                            "\n",
+                            "                                                                  away_team_id  \\\n",
+                            "league             season game                                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                71   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        84   \n",
+                            "                          2015-08-08 Everton-Watford                        90   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   77   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            82   \n",
+                            "\n",
+                            "                                                                          home_team  \\\n",
+                            "league             season game                                                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa            Bournemouth   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        Chelsea   \n",
+                            "                          2015-08-08 Everton-Watford                        Everton   \n",
+                            "                          2015-08-08 Leicester-Sunderland                 Leicester   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  Manchester United   \n",
+                            "\n",
+                            "                                                                    away_team  \\\n",
+                            "league             season game                                                  \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      Aston Villa   \n",
+                            "                          2015-08-08 Chelsea-Swansea                  Swansea   \n",
+                            "                          2015-08-08 Everton-Watford                  Watford   \n",
+                            "                          2015-08-08 Leicester-Sunderland          Sunderland   \n",
+                            "                          2015-08-08 Manchester United-Tottenham    Tottenham   \n",
+                            "\n",
+                            "                                                                 away_team_code  \\\n",
+                            "league             season game                                                    \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                AVL   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        SWA   \n",
+                            "                          2015-08-08 Everton-Watford                        WAT   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   SUN   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            TOT   \n",
+                            "\n",
+                            "                                                                 home_team_code  \\\n",
+                            "league             season game                                                    \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                BOU   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        CHE   \n",
+                            "                          2015-08-08 Everton-Watford                        EVE   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   LEI   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            MUN   \n",
+                            "\n",
+                            "                                                                  home_goals  \\\n",
+                            "league             season game                                                 \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa               0   \n",
+                            "                          2015-08-08 Chelsea-Swansea                       2   \n",
+                            "                          2015-08-08 Everton-Watford                       2   \n",
+                            "                          2015-08-08 Leicester-Sunderland                  4   \n",
+                            "                          2015-08-08 Manchester United-Tottenham           1   \n",
+                            "\n",
+                            "                                                                  away_goals  \\\n",
+                            "league             season game                                                 \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa               1   \n",
+                            "                          2015-08-08 Chelsea-Swansea                       2   \n",
+                            "                          2015-08-08 Everton-Watford                       2   \n",
+                            "                          2015-08-08 Leicester-Sunderland                  2   \n",
+                            "                          2015-08-08 Manchester United-Tottenham           0   \n",
+                            "\n",
+                            "                                                                   home_xg  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      0.876106   \n",
+                            "                          2015-08-08 Chelsea-Swansea               0.64396   \n",
+                            "                          2015-08-08 Everton-Watford              0.604226   \n",
+                            "                          2015-08-08 Leicester-Sunderland          2.56803   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  0.627539   \n",
+                            "\n",
+                            "                                                                   away_xg  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      0.782253   \n",
+                            "                          2015-08-08 Chelsea-Swansea               2.59203   \n",
+                            "                          2015-08-08 Everton-Watford              0.557892   \n",
+                            "                          2015-08-08 Leicester-Sunderland          1.45946   \n",
+                            "                          2015-08-08 Manchester United-Tottenham    0.6746   \n",
+                            "\n",
+                            "                                                                  is_result  \\\n",
+                            "league             season game                                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa           True   \n",
+                            "                          2015-08-08 Chelsea-Swansea                   True   \n",
+                            "                          2015-08-08 Everton-Watford                   True   \n",
+                            "                          2015-08-08 Leicester-Sunderland              True   \n",
+                            "                          2015-08-08 Manchester United-Tottenham       True   \n",
+                            "\n",
+                            "                                                                  has_data  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa          True   \n",
+                            "                          2015-08-08 Chelsea-Swansea                  True   \n",
+                            "                          2015-08-08 Everton-Watford                  True   \n",
+                            "                          2015-08-08 Leicester-Sunderland             True   \n",
+                            "                          2015-08-08 Manchester United-Tottenham      True   \n",
+                            "\n",
+                            "                                                                                             url  \n",
+                            "league             season game                                                                    \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      https://understat.com/match/82  \n",
+                            "                          2015-08-08 Chelsea-Swansea              https://understat.com/match/86  \n",
+                            "                          2015-08-08 Everton-Watford              https://understat.com/match/83  \n",
+                            "                          2015-08-08 Leicester-Sunderland         https://understat.com/match/84  \n",
+                            "                          2015-08-08 Manchester United-Tottenham  https://understat.com/match/81  "
+                        ]
+                    },
+                    "execution_count": 6,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "schedule = understat.read_schedule()\n",
+                "schedule.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "7bd05a01",
+            "metadata": {},
+            "source": [
+                "## Team match stats"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 7,
+            "id": "bc789ef7",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>game_id</th>\n",
+                            "      <th>date</th>\n",
+                            "      <th>home_team_id</th>\n",
+                            "      <th>away_team_id</th>\n",
+                            "      <th>home_team</th>\n",
+                            "      <th>away_team</th>\n",
+                            "      <th>away_team_code</th>\n",
+                            "      <th>home_team_code</th>\n",
+                            "      <th>...</th>\n",
+                            "      <th>away_ppda</th>\n",
+                            "      <th>away_deep_completions</th>\n",
+                            "      <th>home_points</th>\n",
+                            "      <th>home_expected_points</th>\n",
+                            "      <th>home_goals</th>\n",
+                            "      <th>home_xg</th>\n",
+                            "      <th>home_np_xg</th>\n",
+                            "      <th>home_np_xg_difference</th>\n",
+                            "      <th>home_ppda</th>\n",
+                            "      <th>home_deep_completions</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th>game</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">ENG-Premier League</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">1516</th>\n",
+                            "      <th>2015-08-08 Bournemouth-Aston Villa</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>73</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>Bournemouth</td>\n",
+                            "      <td>Aston Villa</td>\n",
+                            "      <td>AVL</td>\n",
+                            "      <td>BOU</td>\n",
+                            "      <td>...</td>\n",
+                            "      <td>11.846154</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>1.3912</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.876106</td>\n",
+                            "      <td>0.876106</td>\n",
+                            "      <td>0.093853</td>\n",
+                            "      <td>6.9</td>\n",
+                            "      <td>11</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Chelsea-Swansea</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>86</td>\n",
+                            "      <td>2015-08-08 20:30:00</td>\n",
+                            "      <td>80</td>\n",
+                            "      <td>84</td>\n",
+                            "      <td>Chelsea</td>\n",
+                            "      <td>Swansea</td>\n",
+                            "      <td>SWA</td>\n",
+                            "      <td>CHE</td>\n",
+                            "      <td>...</td>\n",
+                            "      <td>8.833333</td>\n",
+                            "      <td>5</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0.1836</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0.64396</td>\n",
+                            "      <td>0.64396</td>\n",
+                            "      <td>-1.1869</td>\n",
+                            "      <td>10.363636</td>\n",
+                            "      <td>10</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Everton-Watford</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>83</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>72</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>Everton</td>\n",
+                            "      <td>Watford</td>\n",
+                            "      <td>WAT</td>\n",
+                            "      <td>EVE</td>\n",
+                            "      <td>...</td>\n",
+                            "      <td>17.157895</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>1.3301</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0.604226</td>\n",
+                            "      <td>0.604226</td>\n",
+                            "      <td>0.046334</td>\n",
+                            "      <td>6.65</td>\n",
+                            "      <td>5</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Leicester-Sunderland</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>84</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>75</td>\n",
+                            "      <td>77</td>\n",
+                            "      <td>Leicester</td>\n",
+                            "      <td>Sunderland</td>\n",
+                            "      <td>SUN</td>\n",
+                            "      <td>LEI</td>\n",
+                            "      <td>...</td>\n",
+                            "      <td>9.555556</td>\n",
+                            "      <td>6</td>\n",
+                            "      <td>3</td>\n",
+                            "      <td>2.1323</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>2.56803</td>\n",
+                            "      <td>1.80686</td>\n",
+                            "      <td>0.3474</td>\n",
+                            "      <td>10.88</td>\n",
+                            "      <td>5</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>2015-08-08 Manchester United-Tottenham</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>81</td>\n",
+                            "      <td>2015-08-08 15:45:00</td>\n",
+                            "      <td>89</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>Manchester United</td>\n",
+                            "      <td>Tottenham</td>\n",
+                            "      <td>TOT</td>\n",
+                            "      <td>MUN</td>\n",
+                            "      <td>...</td>\n",
+                            "      <td>8.21875</td>\n",
+                            "      <td>10</td>\n",
+                            "      <td>3</td>\n",
+                            "      <td>1.2482</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0.627539</td>\n",
+                            "      <td>0.627539</td>\n",
+                            "      <td>-0.047061</td>\n",
+                            "      <td>13.826087</td>\n",
+                            "      <td>4</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "<p>5 rows × 26 columns</p>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                                                                 league_id  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa             1   \n",
+                            "                          2015-08-08 Chelsea-Swansea                     1   \n",
+                            "                          2015-08-08 Everton-Watford                     1   \n",
+                            "                          2015-08-08 Leicester-Sunderland                1   \n",
+                            "                          2015-08-08 Manchester United-Tottenham         1   \n",
+                            "\n",
+                            "                                                                  season_id  \\\n",
+                            "league             season game                                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa           2015   \n",
+                            "                          2015-08-08 Chelsea-Swansea                   2015   \n",
+                            "                          2015-08-08 Everton-Watford                   2015   \n",
+                            "                          2015-08-08 Leicester-Sunderland              2015   \n",
+                            "                          2015-08-08 Manchester United-Tottenham       2015   \n",
+                            "\n",
+                            "                                                                  game_id  \\\n",
+                            "league             season game                                              \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa           82   \n",
+                            "                          2015-08-08 Chelsea-Swansea                   86   \n",
+                            "                          2015-08-08 Everton-Watford                   83   \n",
+                            "                          2015-08-08 Leicester-Sunderland              84   \n",
+                            "                          2015-08-08 Manchester United-Tottenham       81   \n",
+                            "\n",
+                            "                                                                                date  \\\n",
+                            "league             season game                                                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa     2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Chelsea-Swansea             2015-08-08 20:30:00   \n",
+                            "                          2015-08-08 Everton-Watford             2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Leicester-Sunderland        2015-08-08 18:00:00   \n",
+                            "                          2015-08-08 Manchester United-Tottenham 2015-08-08 15:45:00   \n",
+                            "\n",
+                            "                                                                  home_team_id  \\\n",
+                            "league             season game                                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                73   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        80   \n",
+                            "                          2015-08-08 Everton-Watford                        72   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   75   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            89   \n",
+                            "\n",
+                            "                                                                  away_team_id  \\\n",
+                            "league             season game                                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                71   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        84   \n",
+                            "                          2015-08-08 Everton-Watford                        90   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   77   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            82   \n",
+                            "\n",
+                            "                                                                          home_team  \\\n",
+                            "league             season game                                                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa            Bournemouth   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        Chelsea   \n",
+                            "                          2015-08-08 Everton-Watford                        Everton   \n",
+                            "                          2015-08-08 Leicester-Sunderland                 Leicester   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  Manchester United   \n",
+                            "\n",
+                            "                                                                    away_team  \\\n",
+                            "league             season game                                                  \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      Aston Villa   \n",
+                            "                          2015-08-08 Chelsea-Swansea                  Swansea   \n",
+                            "                          2015-08-08 Everton-Watford                  Watford   \n",
+                            "                          2015-08-08 Leicester-Sunderland          Sunderland   \n",
+                            "                          2015-08-08 Manchester United-Tottenham    Tottenham   \n",
+                            "\n",
+                            "                                                                 away_team_code  \\\n",
+                            "league             season game                                                    \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                AVL   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        SWA   \n",
+                            "                          2015-08-08 Everton-Watford                        WAT   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   SUN   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            TOT   \n",
+                            "\n",
+                            "                                                                 home_team_code  \\\n",
+                            "league             season game                                                    \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                BOU   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        CHE   \n",
+                            "                          2015-08-08 Everton-Watford                        EVE   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   LEI   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            MUN   \n",
+                            "\n",
+                            "                                                                  ...  \\\n",
+                            "league             season game                                    ...   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      ...   \n",
+                            "                          2015-08-08 Chelsea-Swansea              ...   \n",
+                            "                          2015-08-08 Everton-Watford              ...   \n",
+                            "                          2015-08-08 Leicester-Sunderland         ...   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  ...   \n",
+                            "\n",
+                            "                                                                  away_ppda  \\\n",
+                            "league             season game                                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      11.846154   \n",
+                            "                          2015-08-08 Chelsea-Swansea               8.833333   \n",
+                            "                          2015-08-08 Everton-Watford              17.157895   \n",
+                            "                          2015-08-08 Leicester-Sunderland          9.555556   \n",
+                            "                          2015-08-08 Manchester United-Tottenham    8.21875   \n",
+                            "\n",
+                            "                                                                  away_deep_completions  \\\n",
+                            "league             season game                                                            \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                          2   \n",
+                            "                          2015-08-08 Chelsea-Swansea                                  5   \n",
+                            "                          2015-08-08 Everton-Watford                                  4   \n",
+                            "                          2015-08-08 Leicester-Sunderland                             6   \n",
+                            "                          2015-08-08 Manchester United-Tottenham                     10   \n",
+                            "\n",
+                            "                                                                  home_points  \\\n",
+                            "league             season game                                                  \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                0   \n",
+                            "                          2015-08-08 Chelsea-Swansea                        1   \n",
+                            "                          2015-08-08 Everton-Watford                        1   \n",
+                            "                          2015-08-08 Leicester-Sunderland                   3   \n",
+                            "                          2015-08-08 Manchester United-Tottenham            3   \n",
+                            "\n",
+                            "                                                                  home_expected_points  \\\n",
+                            "league             season game                                                           \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                    1.3912   \n",
+                            "                          2015-08-08 Chelsea-Swansea                            0.1836   \n",
+                            "                          2015-08-08 Everton-Watford                            1.3301   \n",
+                            "                          2015-08-08 Leicester-Sunderland                       2.1323   \n",
+                            "                          2015-08-08 Manchester United-Tottenham                1.2482   \n",
+                            "\n",
+                            "                                                                  home_goals  \\\n",
+                            "league             season game                                                 \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa               0   \n",
+                            "                          2015-08-08 Chelsea-Swansea                       2   \n",
+                            "                          2015-08-08 Everton-Watford                       2   \n",
+                            "                          2015-08-08 Leicester-Sunderland                  4   \n",
+                            "                          2015-08-08 Manchester United-Tottenham           1   \n",
+                            "\n",
+                            "                                                                   home_xg  \\\n",
+                            "league             season game                                               \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa      0.876106   \n",
+                            "                          2015-08-08 Chelsea-Swansea               0.64396   \n",
+                            "                          2015-08-08 Everton-Watford              0.604226   \n",
+                            "                          2015-08-08 Leicester-Sunderland          2.56803   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  0.627539   \n",
+                            "\n",
+                            "                                                                  home_np_xg  \\\n",
+                            "league             season game                                                 \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa        0.876106   \n",
+                            "                          2015-08-08 Chelsea-Swansea                 0.64396   \n",
+                            "                          2015-08-08 Everton-Watford                0.604226   \n",
+                            "                          2015-08-08 Leicester-Sunderland            1.80686   \n",
+                            "                          2015-08-08 Manchester United-Tottenham    0.627539   \n",
+                            "\n",
+                            "                                                                  home_np_xg_difference  \\\n",
+                            "league             season game                                                            \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                   0.093853   \n",
+                            "                          2015-08-08 Chelsea-Swansea                            -1.1869   \n",
+                            "                          2015-08-08 Everton-Watford                           0.046334   \n",
+                            "                          2015-08-08 Leicester-Sunderland                        0.3474   \n",
+                            "                          2015-08-08 Manchester United-Tottenham              -0.047061   \n",
+                            "\n",
+                            "                                                                  home_ppda  \\\n",
+                            "league             season game                                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa            6.9   \n",
+                            "                          2015-08-08 Chelsea-Swansea              10.363636   \n",
+                            "                          2015-08-08 Everton-Watford                   6.65   \n",
+                            "                          2015-08-08 Leicester-Sunderland             10.88   \n",
+                            "                          2015-08-08 Manchester United-Tottenham  13.826087   \n",
+                            "\n",
+                            "                                                                  home_deep_completions  \n",
+                            "league             season game                                                           \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa                         11  \n",
+                            "                          2015-08-08 Chelsea-Swansea                                 10  \n",
+                            "                          2015-08-08 Everton-Watford                                  5  \n",
+                            "                          2015-08-08 Leicester-Sunderland                             5  \n",
+                            "                          2015-08-08 Manchester United-Tottenham                      4  \n",
+                            "\n",
+                            "[5 rows x 26 columns]"
+                        ]
+                    },
+                    "execution_count": 7,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "team_match_stats = understat.read_team_match_stats()\n",
+                "team_match_stats.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "7c07e843",
+            "metadata": {},
+            "source": [
+                "## Player season stats"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 8,
+            "id": "4b9cb8d8",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>team</th>\n",
+                            "      <th>team_id</th>\n",
+                            "      <th>player_id</th>\n",
+                            "      <th>position</th>\n",
+                            "      <th>matches</th>\n",
+                            "      <th>minutes</th>\n",
+                            "      <th>goals</th>\n",
+                            "      <th>xg</th>\n",
+                            "      <th>np_goals</th>\n",
+                            "      <th>np_xg</th>\n",
+                            "      <th>assists</th>\n",
+                            "      <th>xa</th>\n",
+                            "      <th>shots</th>\n",
+                            "      <th>key_passes</th>\n",
+                            "      <th>yellow_cards</th>\n",
+                            "      <th>red_cards</th>\n",
+                            "      <th>xg_chain</th>\n",
+                            "      <th>xg_buildup</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th>player</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">ENG-Premier League</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">1516</th>\n",
+                            "      <th>Aaron Cresswell</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>West Ham</td>\n",
+                            "      <td>81</td>\n",
+                            "      <td>534</td>\n",
+                            "      <td>D M</td>\n",
+                            "      <td>37</td>\n",
+                            "      <td>3319</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>1.092563</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>1.092563</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>3.294618</td>\n",
+                            "      <td>28</td>\n",
+                            "      <td>40</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>10.339367</td>\n",
+                            "      <td>6.831139</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Aaron Lennon</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>Everton</td>\n",
+                            "      <td>72</td>\n",
+                            "      <td>593</td>\n",
+                            "      <td>F M S</td>\n",
+                            "      <td>25</td>\n",
+                            "      <td>1534</td>\n",
+                            "      <td>5</td>\n",
+                            "      <td>2.226095</td>\n",
+                            "      <td>5</td>\n",
+                            "      <td>2.226095</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>1.697951</td>\n",
+                            "      <td>18</td>\n",
+                            "      <td>23</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>5.535392</td>\n",
+                            "      <td>1.90374</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Aaron Ramsey</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>Arsenal</td>\n",
+                            "      <td>83</td>\n",
+                            "      <td>504</td>\n",
+                            "      <td>M S</td>\n",
+                            "      <td>31</td>\n",
+                            "      <td>2624</td>\n",
+                            "      <td>5</td>\n",
+                            "      <td>8.614323</td>\n",
+                            "      <td>5</td>\n",
+                            "      <td>8.614323</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>4.046242</td>\n",
+                            "      <td>69</td>\n",
+                            "      <td>37</td>\n",
+                            "      <td>4</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>23.282566</td>\n",
+                            "      <td>14.176444</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Abdul Rahman Baba</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>Chelsea</td>\n",
+                            "      <td>80</td>\n",
+                            "      <td>684</td>\n",
+                            "      <td>D S</td>\n",
+                            "      <td>15</td>\n",
+                            "      <td>1018</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.379115</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.379115</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0.179241</td>\n",
+                            "      <td>6</td>\n",
+                            "      <td>3</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>3.869669</td>\n",
+                            "      <td>3.490554</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Adam Bogdan</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>Liverpool</td>\n",
+                            "      <td>87</td>\n",
+                            "      <td>698</td>\n",
+                            "      <td>GK</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>180</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.120216</td>\n",
+                            "      <td>0.120216</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                                            league_id  season_id       team  \\\n",
+                            "league             season player                                              \n",
+                            "ENG-Premier League 1516   Aaron Cresswell           1       2015   West Ham   \n",
+                            "                          Aaron Lennon              1       2015    Everton   \n",
+                            "                          Aaron Ramsey              1       2015    Arsenal   \n",
+                            "                          Abdul Rahman Baba         1       2015    Chelsea   \n",
+                            "                          Adam Bogdan               1       2015  Liverpool   \n",
+                            "\n",
+                            "                                             team_id  player_id position  \\\n",
+                            "league             season player                                           \n",
+                            "ENG-Premier League 1516   Aaron Cresswell         81        534      D M   \n",
+                            "                          Aaron Lennon            72        593    F M S   \n",
+                            "                          Aaron Ramsey            83        504      M S   \n",
+                            "                          Abdul Rahman Baba       80        684      D S   \n",
+                            "                          Adam Bogdan             87        698       GK   \n",
+                            "\n",
+                            "                                             matches  minutes  goals  \\\n",
+                            "league             season player                                       \n",
+                            "ENG-Premier League 1516   Aaron Cresswell         37     3319      2   \n",
+                            "                          Aaron Lennon            25     1534      5   \n",
+                            "                          Aaron Ramsey            31     2624      5   \n",
+                            "                          Abdul Rahman Baba       15     1018      0   \n",
+                            "                          Adam Bogdan              2      180      0   \n",
+                            "\n",
+                            "                                                   xg  np_goals     np_xg  \\\n",
+                            "league             season player                                            \n",
+                            "ENG-Premier League 1516   Aaron Cresswell    1.092563         2  1.092563   \n",
+                            "                          Aaron Lennon       2.226095         5  2.226095   \n",
+                            "                          Aaron Ramsey       8.614323         5  8.614323   \n",
+                            "                          Abdul Rahman Baba  0.379115         0  0.379115   \n",
+                            "                          Adam Bogdan             0.0         0       0.0   \n",
+                            "\n",
+                            "                                             assists        xa  shots  \\\n",
+                            "league             season player                                        \n",
+                            "ENG-Premier League 1516   Aaron Cresswell          4  3.294618     28   \n",
+                            "                          Aaron Lennon             0  1.697951     18   \n",
+                            "                          Aaron Ramsey             4  4.046242     69   \n",
+                            "                          Abdul Rahman Baba        1  0.179241      6   \n",
+                            "                          Adam Bogdan              0       0.0      0   \n",
+                            "\n",
+                            "                                             key_passes  yellow_cards  \\\n",
+                            "league             season player                                        \n",
+                            "ENG-Premier League 1516   Aaron Cresswell            40             1   \n",
+                            "                          Aaron Lennon               23             1   \n",
+                            "                          Aaron Ramsey               37             4   \n",
+                            "                          Abdul Rahman Baba           3             1   \n",
+                            "                          Adam Bogdan                 0             0   \n",
+                            "\n",
+                            "                                             red_cards   xg_chain  xg_buildup  \n",
+                            "league             season player                                               \n",
+                            "ENG-Premier League 1516   Aaron Cresswell            0  10.339367    6.831139  \n",
+                            "                          Aaron Lennon               0   5.535392     1.90374  \n",
+                            "                          Aaron Ramsey               0  23.282566   14.176444  \n",
+                            "                          Abdul Rahman Baba          0   3.869669    3.490554  \n",
+                            "                          Adam Bogdan                0   0.120216    0.120216  "
+                        ]
+                    },
+                    "execution_count": 8,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "player_season_stats = understat.read_player_season_stats()\n",
+                "player_season_stats.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "04162974",
+            "metadata": {},
+            "source": [
+                "## Player match stats"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 9,
+            "id": "5ef60999",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>game_id</th>\n",
+                            "      <th>team_id</th>\n",
+                            "      <th>player_id</th>\n",
+                            "      <th>position</th>\n",
+                            "      <th>position_id</th>\n",
+                            "      <th>minutes</th>\n",
+                            "      <th>goals</th>\n",
+                            "      <th>own_goals</th>\n",
+                            "      <th>shots</th>\n",
+                            "      <th>xg</th>\n",
+                            "      <th>xa</th>\n",
+                            "      <th>xg_chain</th>\n",
+                            "      <th>xg_buildup</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th>game</th>\n",
+                            "      <th>team</th>\n",
+                            "      <th>player</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">ENG-Premier League</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">1516</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">2015-08-08 Bournemouth-Aston Villa</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">Aston Villa</th>\n",
+                            "      <th>Ashley Westwood</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>669</td>\n",
+                            "      <td>MC</td>\n",
+                            "      <td>9</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.374082</td>\n",
+                            "      <td>0.131937</td>\n",
+                            "      <td>0.131937</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Brad Guzan</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>662</td>\n",
+                            "      <td>GK</td>\n",
+                            "      <td>1</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Carlos Sánchez</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>667</td>\n",
+                            "      <td>Sub</td>\n",
+                            "      <td>17</td>\n",
+                            "      <td>18</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Ciaran Clark</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>875</td>\n",
+                            "      <td>DC</td>\n",
+                            "      <td>3</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.0</td>\n",
+                            "      <td>0.131937</td>\n",
+                            "      <td>0.131937</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Gabriel Agbonlahor</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>890</td>\n",
+                            "      <td>FW</td>\n",
+                            "      <td>15</td>\n",
+                            "      <td>90</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>0</td>\n",
+                            "      <td>2</td>\n",
+                            "      <td>0.13016</td>\n",
+                            "      <td>0.113668</td>\n",
+                            "      <td>0.243828</td>\n",
+                            "      <td>0.0</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                                                                                            league_id  \\\n",
+                            "league             season game                               team        player                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood            1   \n",
+                            "                                                                         Brad Guzan                 1   \n",
+                            "                                                                         Carlos Sánchez             1   \n",
+                            "                                                                         Ciaran Clark               1   \n",
+                            "                                                                         Gabriel Agbonlahor         1   \n",
+                            "\n",
+                            "                                                                                             season_id  \\\n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood          2015   \n",
+                            "                                                                         Brad Guzan               2015   \n",
+                            "                                                                         Carlos Sánchez           2015   \n",
+                            "                                                                         Ciaran Clark             2015   \n",
+                            "                                                                         Gabriel Agbonlahor       2015   \n",
+                            "\n",
+                            "                                                                                             game_id  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood          82   \n",
+                            "                                                                         Brad Guzan               82   \n",
+                            "                                                                         Carlos Sánchez           82   \n",
+                            "                                                                         Ciaran Clark             82   \n",
+                            "                                                                         Gabriel Agbonlahor       82   \n",
+                            "\n",
+                            "                                                                                             team_id  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood          71   \n",
+                            "                                                                         Brad Guzan               71   \n",
+                            "                                                                         Carlos Sánchez           71   \n",
+                            "                                                                         Ciaran Clark             71   \n",
+                            "                                                                         Gabriel Agbonlahor       71   \n",
+                            "\n",
+                            "                                                                                             player_id  \\\n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood           669   \n",
+                            "                                                                         Brad Guzan                662   \n",
+                            "                                                                         Carlos Sánchez            667   \n",
+                            "                                                                         Ciaran Clark              875   \n",
+                            "                                                                         Gabriel Agbonlahor        890   \n",
+                            "\n",
+                            "                                                                                            position  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood          MC   \n",
+                            "                                                                         Brad Guzan               GK   \n",
+                            "                                                                         Carlos Sánchez          Sub   \n",
+                            "                                                                         Ciaran Clark             DC   \n",
+                            "                                                                         Gabriel Agbonlahor       FW   \n",
+                            "\n",
+                            "                                                                                             position_id  \\\n",
+                            "league             season game                               team        player                            \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood               9   \n",
+                            "                                                                         Brad Guzan                    1   \n",
+                            "                                                                         Carlos Sánchez               17   \n",
+                            "                                                                         Ciaran Clark                  3   \n",
+                            "                                                                         Gabriel Agbonlahor           15   \n",
+                            "\n",
+                            "                                                                                             minutes  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood          90   \n",
+                            "                                                                         Brad Guzan               90   \n",
+                            "                                                                         Carlos Sánchez           18   \n",
+                            "                                                                         Ciaran Clark             90   \n",
+                            "                                                                         Gabriel Agbonlahor       90   \n",
+                            "\n",
+                            "                                                                                             goals  \\\n",
+                            "league             season game                               team        player                      \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood         0   \n",
+                            "                                                                         Brad Guzan              0   \n",
+                            "                                                                         Carlos Sánchez          0   \n",
+                            "                                                                         Ciaran Clark            0   \n",
+                            "                                                                         Gabriel Agbonlahor      0   \n",
+                            "\n",
+                            "                                                                                             own_goals  \\\n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood             0   \n",
+                            "                                                                         Brad Guzan                  0   \n",
+                            "                                                                         Carlos Sánchez              0   \n",
+                            "                                                                         Ciaran Clark                0   \n",
+                            "                                                                         Gabriel Agbonlahor          0   \n",
+                            "\n",
+                            "                                                                                             shots  \\\n",
+                            "league             season game                               team        player                      \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood         0   \n",
+                            "                                                                         Brad Guzan              0   \n",
+                            "                                                                         Carlos Sánchez          0   \n",
+                            "                                                                         Ciaran Clark            0   \n",
+                            "                                                                         Gabriel Agbonlahor      2   \n",
+                            "\n",
+                            "                                                                                                  xg  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood         0.0   \n",
+                            "                                                                         Brad Guzan              0.0   \n",
+                            "                                                                         Carlos Sánchez          0.0   \n",
+                            "                                                                         Ciaran Clark            0.0   \n",
+                            "                                                                         Gabriel Agbonlahor  0.13016   \n",
+                            "\n",
+                            "                                                                                                   xa  \\\n",
+                            "league             season game                               team        player                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood     0.374082   \n",
+                            "                                                                         Brad Guzan               0.0   \n",
+                            "                                                                         Carlos Sánchez           0.0   \n",
+                            "                                                                         Ciaran Clark             0.0   \n",
+                            "                                                                         Gabriel Agbonlahor  0.113668   \n",
+                            "\n",
+                            "                                                                                             xg_chain  \\\n",
+                            "league             season game                               team        player                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood     0.131937   \n",
+                            "                                                                         Brad Guzan               0.0   \n",
+                            "                                                                         Carlos Sánchez           0.0   \n",
+                            "                                                                         Ciaran Clark        0.131937   \n",
+                            "                                                                         Gabriel Agbonlahor  0.243828   \n",
+                            "\n",
+                            "                                                                                             xg_buildup  \n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Ashley Westwood       0.131937  \n",
+                            "                                                                         Brad Guzan                 0.0  \n",
+                            "                                                                         Carlos Sánchez             0.0  \n",
+                            "                                                                         Ciaran Clark          0.131937  \n",
+                            "                                                                         Gabriel Agbonlahor         0.0  "
+                        ]
+                    },
+                    "execution_count": 9,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "player_match_stats = understat.read_player_match_stats()\n",
+                "player_match_stats.head()"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "6da5002a",
+            "metadata": {},
+            "source": [
+                "## Shot events"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 10,
+            "id": "aad9366c",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/html": [
+                            "<div>\n",
+                            "<style scoped>\n",
+                            "    .dataframe tbody tr th:only-of-type {\n",
+                            "        vertical-align: middle;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe tbody tr th {\n",
+                            "        vertical-align: top;\n",
+                            "    }\n",
+                            "\n",
+                            "    .dataframe thead th {\n",
+                            "        text-align: right;\n",
+                            "    }\n",
+                            "</style>\n",
+                            "<table border=\"1\" class=\"dataframe\">\n",
+                            "  <thead>\n",
+                            "    <tr style=\"text-align: right;\">\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th>league_id</th>\n",
+                            "      <th>season_id</th>\n",
+                            "      <th>game_id</th>\n",
+                            "      <th>date</th>\n",
+                            "      <th>shot_id</th>\n",
+                            "      <th>team_id</th>\n",
+                            "      <th>player_id</th>\n",
+                            "      <th>assist_player_id</th>\n",
+                            "      <th>assist_player</th>\n",
+                            "      <th>xg</th>\n",
+                            "      <th>location_x</th>\n",
+                            "      <th>location_y</th>\n",
+                            "      <th>minute</th>\n",
+                            "      <th>body_part</th>\n",
+                            "      <th>situation</th>\n",
+                            "      <th>result</th>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>league</th>\n",
+                            "      <th>season</th>\n",
+                            "      <th>game</th>\n",
+                            "      <th>team</th>\n",
+                            "      <th>player</th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "      <th></th>\n",
+                            "    </tr>\n",
+                            "  </thead>\n",
+                            "  <tbody>\n",
+                            "    <tr>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">ENG-Premier League</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">1516</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">2015-08-08 Bournemouth-Aston Villa</th>\n",
+                            "      <th rowspan=\"5\" valign=\"top\">Aston Villa</th>\n",
+                            "      <th>Gabriel Agbonlahor</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>487146</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>890</td>\n",
+                            "      <td>&lt;NA&gt;</td>\n",
+                            "      <td>&lt;NA&gt;</td>\n",
+                            "      <td>0.075484</td>\n",
+                            "      <td>0.86</td>\n",
+                            "      <td>0.503</td>\n",
+                            "      <td>67</td>\n",
+                            "      <td>Left Foot</td>\n",
+                            "      <td>Open Play</td>\n",
+                            "      <td>Blocked Shot</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Gabriel Agbonlahor</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>487150</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>890</td>\n",
+                            "      <td>548651</td>\n",
+                            "      <td>Micah Richards</td>\n",
+                            "      <td>0.054676</td>\n",
+                            "      <td>0.795</td>\n",
+                            "      <td>0.507</td>\n",
+                            "      <td>81</td>\n",
+                            "      <td>Left Foot</td>\n",
+                            "      <td>Open Play</td>\n",
+                            "      <td>Saved Shot</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Idrissa Gueye</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>487136</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>668</td>\n",
+                            "      <td>548653</td>\n",
+                            "      <td>Jordan Veretout</td>\n",
+                            "      <td>0.018269</td>\n",
+                            "      <td>0.742</td>\n",
+                            "      <td>0.598</td>\n",
+                            "      <td>26</td>\n",
+                            "      <td>Right Foot</td>\n",
+                            "      <td>Open Play</td>\n",
+                            "      <td>Missed Shot</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Idrissa Gueye</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>487144</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>668</td>\n",
+                            "      <td>548657</td>\n",
+                            "      <td>Gabriel Agbonlahor</td>\n",
+                            "      <td>0.113668</td>\n",
+                            "      <td>0.883</td>\n",
+                            "      <td>0.561</td>\n",
+                            "      <td>47</td>\n",
+                            "      <td>Left Foot</td>\n",
+                            "      <td>Open Play</td>\n",
+                            "      <td>Saved Shot</td>\n",
+                            "    </tr>\n",
+                            "    <tr>\n",
+                            "      <th>Leandro Bacuna</th>\n",
+                            "      <td>1</td>\n",
+                            "      <td>2015</td>\n",
+                            "      <td>82</td>\n",
+                            "      <td>2015-08-08 18:00:00</td>\n",
+                            "      <td>487141</td>\n",
+                            "      <td>71</td>\n",
+                            "      <td>674</td>\n",
+                            "      <td>&lt;NA&gt;</td>\n",
+                            "      <td>&lt;NA&gt;</td>\n",
+                            "      <td>0.097371</td>\n",
+                            "      <td>0.786</td>\n",
+                            "      <td>0.437</td>\n",
+                            "      <td>42</td>\n",
+                            "      <td>Right Foot</td>\n",
+                            "      <td>Direct Freekick</td>\n",
+                            "      <td>Blocked Shot</td>\n",
+                            "    </tr>\n",
+                            "  </tbody>\n",
+                            "</table>\n",
+                            "</div>"
+                        ],
+                        "text/plain": [
+                            "                                                                                            league_id  \\\n",
+                            "league             season game                               team        player                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor         1   \n",
+                            "                                                                         Gabriel Agbonlahor         1   \n",
+                            "                                                                         Idrissa Gueye              1   \n",
+                            "                                                                         Idrissa Gueye              1   \n",
+                            "                                                                         Leandro Bacuna             1   \n",
+                            "\n",
+                            "                                                                                             season_id  \\\n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor       2015   \n",
+                            "                                                                         Gabriel Agbonlahor       2015   \n",
+                            "                                                                         Idrissa Gueye            2015   \n",
+                            "                                                                         Idrissa Gueye            2015   \n",
+                            "                                                                         Leandro Bacuna           2015   \n",
+                            "\n",
+                            "                                                                                             game_id  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor       82   \n",
+                            "                                                                         Gabriel Agbonlahor       82   \n",
+                            "                                                                         Idrissa Gueye            82   \n",
+                            "                                                                         Idrissa Gueye            82   \n",
+                            "                                                                         Leandro Bacuna           82   \n",
+                            "\n",
+                            "                                                                                                           date  \\\n",
+                            "league             season game                               team        player                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor 2015-08-08 18:00:00   \n",
+                            "                                                                         Gabriel Agbonlahor 2015-08-08 18:00:00   \n",
+                            "                                                                         Idrissa Gueye      2015-08-08 18:00:00   \n",
+                            "                                                                         Idrissa Gueye      2015-08-08 18:00:00   \n",
+                            "                                                                         Leandro Bacuna     2015-08-08 18:00:00   \n",
+                            "\n",
+                            "                                                                                             shot_id  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor   487146   \n",
+                            "                                                                         Gabriel Agbonlahor   487150   \n",
+                            "                                                                         Idrissa Gueye        487136   \n",
+                            "                                                                         Idrissa Gueye        487144   \n",
+                            "                                                                         Leandro Bacuna       487141   \n",
+                            "\n",
+                            "                                                                                             team_id  \\\n",
+                            "league             season game                               team        player                        \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor       71   \n",
+                            "                                                                         Gabriel Agbonlahor       71   \n",
+                            "                                                                         Idrissa Gueye            71   \n",
+                            "                                                                         Idrissa Gueye            71   \n",
+                            "                                                                         Leandro Bacuna           71   \n",
+                            "\n",
+                            "                                                                                             player_id  \\\n",
+                            "league             season game                               team        player                          \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor        890   \n",
+                            "                                                                         Gabriel Agbonlahor        890   \n",
+                            "                                                                         Idrissa Gueye             668   \n",
+                            "                                                                         Idrissa Gueye             668   \n",
+                            "                                                                         Leandro Bacuna            674   \n",
+                            "\n",
+                            "                                                                                             assist_player_id  \\\n",
+                            "league             season game                               team        player                                 \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor              <NA>   \n",
+                            "                                                                         Gabriel Agbonlahor            548651   \n",
+                            "                                                                         Idrissa Gueye                 548653   \n",
+                            "                                                                         Idrissa Gueye                 548657   \n",
+                            "                                                                         Leandro Bacuna                  <NA>   \n",
+                            "\n",
+                            "                                                                                                  assist_player  \\\n",
+                            "league             season game                               team        player                                   \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor                <NA>   \n",
+                            "                                                                         Gabriel Agbonlahor      Micah Richards   \n",
+                            "                                                                         Idrissa Gueye          Jordan Veretout   \n",
+                            "                                                                         Idrissa Gueye       Gabriel Agbonlahor   \n",
+                            "                                                                         Leandro Bacuna                    <NA>   \n",
+                            "\n",
+                            "                                                                                                   xg  \\\n",
+                            "league             season game                               team        player                         \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor  0.075484   \n",
+                            "                                                                         Gabriel Agbonlahor  0.054676   \n",
+                            "                                                                         Idrissa Gueye       0.018269   \n",
+                            "                                                                         Idrissa Gueye       0.113668   \n",
+                            "                                                                         Leandro Bacuna      0.097371   \n",
+                            "\n",
+                            "                                                                                             location_x  \\\n",
+                            "league             season game                               team        player                           \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor        0.86   \n",
+                            "                                                                         Gabriel Agbonlahor       0.795   \n",
+                            "                                                                         Idrissa Gueye            0.742   \n",
+                            "                                                                         Idrissa Gueye            0.883   \n",
+                            "                                                                         Leandro Bacuna           0.786   \n",
+                            "\n",
+                            "                                                                                             location_y  \\\n",
+                            "league             season game                               team        player                           \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor       0.503   \n",
+                            "                                                                         Gabriel Agbonlahor       0.507   \n",
+                            "                                                                         Idrissa Gueye            0.598   \n",
+                            "                                                                         Idrissa Gueye            0.561   \n",
+                            "                                                                         Leandro Bacuna           0.437   \n",
+                            "\n",
+                            "                                                                                             minute  \\\n",
+                            "league             season game                               team        player                       \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor      67   \n",
+                            "                                                                         Gabriel Agbonlahor      81   \n",
+                            "                                                                         Idrissa Gueye           26   \n",
+                            "                                                                         Idrissa Gueye           47   \n",
+                            "                                                                         Leandro Bacuna          42   \n",
+                            "\n",
+                            "                                                                                              body_part  \\\n",
+                            "league             season game                               team        player                           \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor   Left Foot   \n",
+                            "                                                                         Gabriel Agbonlahor   Left Foot   \n",
+                            "                                                                         Idrissa Gueye       Right Foot   \n",
+                            "                                                                         Idrissa Gueye        Left Foot   \n",
+                            "                                                                         Leandro Bacuna      Right Foot   \n",
+                            "\n",
+                            "                                                                                                   situation  \\\n",
+                            "league             season game                               team        player                                \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor        Open Play   \n",
+                            "                                                                         Gabriel Agbonlahor        Open Play   \n",
+                            "                                                                         Idrissa Gueye             Open Play   \n",
+                            "                                                                         Idrissa Gueye             Open Play   \n",
+                            "                                                                         Leandro Bacuna      Direct Freekick   \n",
+                            "\n",
+                            "                                                                                                   result  \n",
+                            "league             season game                               team        player                            \n",
+                            "ENG-Premier League 1516   2015-08-08 Bournemouth-Aston Villa Aston Villa Gabriel Agbonlahor  Blocked Shot  \n",
+                            "                                                                         Gabriel Agbonlahor    Saved Shot  \n",
+                            "                                                                         Idrissa Gueye        Missed Shot  \n",
+                            "                                                                         Idrissa Gueye         Saved Shot  \n",
+                            "                                                                         Leandro Bacuna      Blocked Shot  "
+                        ]
+                    },
+                    "execution_count": 10,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "shot_events = understat.read_shot_events()\n",
+                "shot_events.head()"
+            ]
+        }
+    ],
+    "metadata": {
+        "kernelspec": {
+            "display_name": "soccerdata",
+            "language": "python",
+            "name": "soccerdata"
+        },
+        "language_info": {
+            "codemirror_mode": {
+                "name": "ipython",
+                "version": 3
+            },
+            "file_extension": ".py",
+            "mimetype": "text/x-python",
+            "name": "python",
+            "nbconvert_exporter": "python",
+            "pygments_lexer": "ipython3",
+            "version": "3.12.1"
+        },
+        "toc": {
+            "base_numbering": 1,
+            "nav_menu": {},
+            "number_sections": true,
+            "sideBar": true,
+            "skip_h1_title": false,
+            "title_cell": "Table of Contents",
+            "title_sidebar": "Contents",
+            "toc_cell": false,
+            "toc_position": {},
+            "toc_section_display": true,
+            "toc_window_display": true
+        }
+    },
+    "nbformat": 4,
+    "nbformat_minor": 5
+}
diff --git a/docs/datasources/index.rst b/docs/datasources/index.rst
index 906e185d..78e17b3e 100644
--- a/docs/datasources/index.rst
+++ b/docs/datasources/index.rst
@@ -92,6 +92,19 @@ SoFIFA
 
 -----
 
+Understat
+    `URL <https://understat.com>`__ |
+    :doc:`Example usage <Understat>` |
+    :doc:`API reference </reference/understat>`
+
+    .. code::
+
+      from soccerdata import Understat
+
+    Advanced statistics such as xG, xGBuildup and xGChain, and shot events with associated xG values for the top European leagues.
+
+-----
+
 WhoScored
     `URL <https://www.whoscored.com/>`__ |
     :doc:`Example usage <WhoScored>` |
@@ -113,4 +126,5 @@ WhoScored
    FotMob
    MatchHistory
    SoFIFA
+   Understat
    WhoScored
diff --git a/docs/index.rst b/docs/index.rst
index 6a449d7c..29c419ea 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -20,7 +20,7 @@ Release v\ |release|. (``pip install soccerdata``)
 
 **SoccerData** is a collection of scrapers to gather soccer data from popular
 websites, including `Club Elo`_, `ESPN`_, `FBref`_, `FiveThirtyEight`_,
-`Football-Data.co.uk`_, `FotMob`_, `SoFIFA`_ and `WhoScored`_.
+`Football-Data.co.uk`_, `FotMob`_, `SoFIFA`_, `Understat`_  and `WhoScored`_.
 
 .. code:: python
 
@@ -70,8 +70,8 @@ Do you like it? :doc:`Let's dive in! <intro>`
 .. _ESPN: https://www.espn.com/soccer/
 .. _FBref: https://www.fbref.com/en/
 .. _FiveThirtyEight: https://fivethirtyeight.com/soccer-predictions/
-.. _FotMob: https://fotmob.com
 .. _Football-Data.co.uk: https://www.football-data.co.uk/
 .. _FotMob: https://fotmob.com/
 .. _SoFIFA: https://sofifa.com/
+.. _Understat: https://understat.com/
 .. _WhoScored: https://www.whoscored.com/
diff --git a/docs/reference/index.rst b/docs/reference/index.rst
index 009346c5..8c30fc72 100644
--- a/docs/reference/index.rst
+++ b/docs/reference/index.rst
@@ -18,6 +18,7 @@ data scrapers.
    fotmob
    matchhistory
    sofifa
+   understat
    whoscored
 
 If you would like to extend the functionality of soccerdata, you might also be
diff --git a/docs/reference/understat.rst b/docs/reference/understat.rst
new file mode 100644
index 00000000..6ce36218
--- /dev/null
+++ b/docs/reference/understat.rst
@@ -0,0 +1,10 @@
+.. _api-understat:
+
+Understat
+=========
+
+.. autoclass:: soccerdata.Understat
+   :inherited-members: available_leagues
+   :members: read_leagues, read_seasons, read_schedule,
+    read_team_match_stats, read_player_season_stats,
+    read_player_match_stats, read_shot_events
diff --git a/poetry.lock b/poetry.lock
index 49a0f36e..e0af5358 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1368,8 +1368,8 @@ files = [
 [package.dependencies]
 numpy = [
     {version = ">=1.22.4,<2", markers = "python_version < \"3.11\""},
-    {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""},
     {version = ">=1.26.0,<2", markers = "python_version >= \"3.12\""},
+    {version = ">=1.23.2,<2", markers = "python_version == \"3.11\""},
 ]
 python-dateutil = ">=2.8.2"
 pytz = ">=2020.1"
@@ -1579,8 +1579,8 @@ astroid = ">=3.0.1,<=3.1.0-dev0"
 colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
 dill = [
     {version = ">=0.2", markers = "python_version < \"3.11\""},
-    {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
     {version = ">=0.3.7", markers = "python_version >= \"3.12\""},
+    {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
 ]
 isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
 mccabe = ">=0.6,<0.8"
@@ -1731,6 +1731,7 @@ files = [
     {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
     {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
     {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+    {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
     {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
     {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
     {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
@@ -2248,13 +2249,13 @@ test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools
 
 [[package]]
 name = "sphinx-autobuild"
-version = "2021.3.14"
+version = "2024.2.4"
 description = "Rebuild Sphinx documentation on changes, with live-reload in the browser."
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.9"
 files = [
-    {file = "sphinx-autobuild-2021.3.14.tar.gz", hash = "sha256:de1ca3b66e271d2b5b5140c35034c89e47f263f2cd5db302c9217065f7443f05"},
-    {file = "sphinx_autobuild-2021.3.14-py3-none-any.whl", hash = "sha256:8fe8cbfdb75db04475232f05187c776f46f6e9e04cacf1e49ce81bdac649ccac"},
+    {file = "sphinx_autobuild-2024.2.4-py3-none-any.whl", hash = "sha256:63fd87ab7505872a89aef468ce6503f65e794a195f4ae62269db3b85b72d4854"},
+    {file = "sphinx_autobuild-2024.2.4.tar.gz", hash = "sha256:cb9d2121a176d62d45471624872afc5fad7755ad662738abe400ecf4a7954303"},
 ]
 
 [package.dependencies]
@@ -2263,7 +2264,7 @@ livereload = "*"
 sphinx = "*"
 
 [package.extras]
-test = ["pytest", "pytest-cov"]
+test = ["pytest (>=6.0)", "pytest-cov"]
 
 [[package]]
 name = "sphinx-basic-ng"
@@ -2801,4 +2802,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
 [metadata]
 lock-version = "2.0"
 python-versions = ">=3.9,<3.13"
-content-hash = "0b6eae94d59cb9e3115ff5f20a7bc322dab4941cc8a92d2f59664031971aba4f"
+content-hash = "688ae48154b52784fc4c19d0fe0ea676c32dfa195937a192b192408a409c8892"
diff --git a/pyproject.toml b/pyproject.toml
index ae668907..33f8d4be 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,7 +34,7 @@ pytest-deadfixtures = "^2.2.1"
 unify = "^0.5"
 black = "^24.0.0"
 Sphinx = "^7.0.0"
-sphinx-autobuild = "^2021.3.14"
+sphinx-autobuild = "^2024.0.0"
 furo = "^2024.0.0"
 coverage = {version = "^7.0", extras = ["toml"]}
 pre-commit = "^3.0.0"
diff --git a/soccerdata/__init__.py b/soccerdata/__init__.py
index de8af43a..a6cfa5d5 100644
--- a/soccerdata/__init__.py
+++ b/soccerdata/__init__.py
@@ -3,14 +3,15 @@
 __version__ = '1.5.3'
 
 __all__ = [
-    'FiveThirtyEight',
     'ClubElo',
-    'MatchHistory',
+    'ESPN',
     'FBref',
+    'FiveThirtyEight',
     'FotMob',
-    'ESPN',
-    'WhoScored',
+    'MatchHistory',
     'SoFIFA',
+    'Understat',
+    'WhoScored',
 ]
 
 from .clubelo import ClubElo
@@ -20,4 +21,5 @@
 from .fotmob import FotMob
 from .match_history import MatchHistory
 from .sofifa import SoFIFA
+from .understat import Understat
 from .whoscored import WhoScored
diff --git a/soccerdata/_common.py b/soccerdata/_common.py
index f11321e8..a275b800 100644
--- a/soccerdata/_common.py
+++ b/soccerdata/_common.py
@@ -97,7 +97,7 @@ def get(
         filepath: Optional[Path] = None,
         max_age: Optional[Union[int, timedelta]] = MAXAGE,
         no_cache: bool = False,
-        var: Optional[str] = None,
+        var: Optional[Union[str, Iterable[str]]] = None,
     ) -> IO[bytes]:
         """Load data from `url`.
 
@@ -115,8 +115,8 @@ def get(
             The max. age of locally cached file before re-download.
         no_cache : bool
             If True, will not use cached data. Overrides the class property.
-        var : str, optional
-            Return a javascript variable instead of the page source.
+        var : str or list of str, optional
+            Return a JavaScript variable instead of the page source.
 
         Raises
         ------
@@ -186,7 +186,7 @@ def _download_and_save(
         self,
         url: str,
         filepath: Optional[Path] = None,
-        var: Optional[str] = None,
+        var: Optional[Union[str, Iterable[str]]] = None,
     ) -> IO[bytes]:
         """Download data at `url` to `filepath`.
 
@@ -196,8 +196,8 @@ def _download_and_save(
             URL to download.
         filepath : Path, optional
             Path to save downloaded file. If None, downloaded data is not cached.
-        var : str, optional
-            Return a javascript variable instead of the page source.
+        var : str or list of str, optional
+            Return a JavaScript variable instead of the page source.
 
         Returns
         -------
@@ -337,7 +337,7 @@ def _download_and_save(
         self,
         url: str,
         filepath: Optional[Path] = None,
-        var: Optional[str] = None,
+        var: Optional[Union[str, Iterable[str]]] = None,
     ) -> IO[bytes]:
         """Download file at url to filepath. Overwrites if filepath exists."""
         for i in range(5):
@@ -345,10 +345,24 @@ def _download_and_save(
                 response = self._session.get(url, stream=True)
                 time.sleep(self.rate_limit + random.random() * self.max_delay)
                 response.raise_for_status()
+                if var is not None:
+                    if isinstance(var, str):
+                        var = [var]
+                    var_names = "|".join(var)
+                    template_understat = br"(%b)+[\s\t]*=[\s\t]*JSON\.parse\('(.*)'\)"
+                    pattern_understat = template_understat % bytes(var_names, encoding="utf-8")
+                    results = re.findall(pattern_understat, response.content)
+                    data = {
+                        key.decode("unicode_escape"): json.loads(value.decode("unicode_escape"))
+                        for key, value in results
+                    }
+                    payload = json.dumps(data).encode("utf-8")
+                else:
+                    payload = response.content
                 if not self.no_store and filepath is not None:
                     with filepath.open(mode="wb") as fh:
-                        fh.write(response.content)
-                return io.BytesIO(response.content)
+                        fh.write(payload)
+                return io.BytesIO(payload)
             except Exception:
                 logger.exception(
                     "Error while scraping %s. Retrying... (attempt %d of 5).", url, i + 1
@@ -429,7 +443,7 @@ def _download_and_save(  # noqa: C901
         self,
         url: str,
         filepath: Optional[Path] = None,
-        var: Optional[str] = None,
+        var: Optional[Union[str, Iterable[str]]] = None,
     ) -> IO[bytes]:
         """Download file at url to filepath. Overwrites if filepath exists."""
         for i in range(5):
@@ -445,6 +459,8 @@ def _download_and_save(  # noqa: C901
                         "return document.body.innerHTML;"
                     ).encode("utf-8")
                 else:
+                    if not isinstance(var, str):
+                        raise NotImplementedError("Only implemented for single variables.")
                     response = json.dumps(self._driver.execute_script("return " + var)).encode(
                         "utf-8"
                     )
diff --git a/soccerdata/_config.py b/soccerdata/_config.py
index be933cd2..938f00ac 100644
--- a/soccerdata/_config.py
+++ b/soccerdata/_config.py
@@ -100,6 +100,7 @@
         "FotMob": "ENG-Premier League",
         "ESPN": "eng.1",
         "SoFIFA": "[England] Premier League",
+        "Understat": "EPL",
         "WhoScored": "England - Premier League",
         "season_start": "Aug",
         "season_end": "May",
@@ -112,6 +113,7 @@
         "FotMob": "ESP-LaLiga",
         "ESPN": "esp.1",
         "SoFIFA": "[Spain] La Liga",
+        "Understat": "La liga",
         "WhoScored": "Spain - LaLiga",
         "season_start": "Aug",
         "season_end": "May",
@@ -124,6 +126,7 @@
         "FotMob": "ITA-Serie A",
         "ESPN": "ita.1",
         "SoFIFA": "[Italy] Serie A",
+        "Understat": "Serie A",
         "WhoScored": "Italy - Serie A",
         "season_start": "Aug",
         "season_end": "May",
@@ -136,6 +139,7 @@
         "FotMob": "GER-Bundesliga",
         "ESPN": "ger.1",
         "SoFIFA": "[Germany] Bundesliga",
+        "Understat": "Bundesliga",
         "WhoScored": "Germany - Bundesliga",
         "season_start": "Aug",
         "season_end": "May",
@@ -148,6 +152,7 @@
         "FotMob": "FRA-Ligue 1",
         "ESPN": "fra.1",
         "SoFIFA": "[France] Ligue 1",
+        "Understat": "Ligue 1",
         "WhoScored": "France - Ligue 1",
         "season_start": "Aug",
         "season_end": "May",
diff --git a/soccerdata/understat.py b/soccerdata/understat.py
new file mode 100644
index 00000000..94d56695
--- /dev/null
+++ b/soccerdata/understat.py
@@ -0,0 +1,707 @@
+"""Scraper for understat.com."""
+
+import itertools
+import json
+from html import unescape
+from pathlib import Path
+from typing import Any, Callable, Dict, Iterable, List, Optional, Union
+
+import pandas as pd
+
+from ._common import BaseRequestsReader, make_game_id, season_code
+from ._config import DATA_DIR, NOCACHE, NOSTORE, TEAMNAME_REPLACEMENTS
+
+UNDERSTAT_DATADIR = DATA_DIR / "Understat"
+UNDERSTAT_URL = "https://understat.com"
+
+SHOT_SITUATIONS = {
+    "OpenPlay": "Open Play",
+    "FromCorner": "From Corner",
+    "SetPiece": "Set Piece",
+    "DirectFreekick": "Direct Freekick",
+}
+
+SHOT_BODY_PARTS = {
+    "RightFoot": "Right Foot",
+    "LeftFoot": "Left Foot",
+    "OtherBodyParts": "Other",
+}
+
+SHOT_RESULTS = {
+    "Goal": "Goal",
+    "OwnGoal": "Own Goal",
+    "BlockedShot": "Blocked Shot",
+    "SavedShot": "Saved Shot",
+    "MissedShots": "Missed Shot",
+    "ShotOnPost": "Shot On Post",
+}
+
+
+class Understat(BaseRequestsReader):
+    """Provides pd.DataFrames from data at https://understat.com.
+
+    Data will be downloaded as necessary and cached locally in
+    ``~/soccerdata/data/Understat``.
+
+    Parameters
+    ----------
+    proxy : 'tor' or dict or list(dict) or callable, optional
+        Use a proxy to hide your IP address. Valid options are:
+            - "tor": Uses the Tor network. Tor should be running in
+              the background on port 9050.
+            - dict: A dictionary with the proxy to use. The dict should be
+              a mapping of supported protocols to proxy addresses. For example::
+
+                  {
+                      'http': 'http://10.10.1.10:3128',
+                      'https': 'http://10.10.1.10:1080',
+                  }
+
+            - list(dict): A list of proxies to choose from. A different proxy will
+              be selected from this list after failed requests, allowing rotating
+              proxies.
+            - callable: A function that returns a valid proxy. This function will
+              be called after failed requests, allowing rotating proxies.
+    no_cache : bool
+        If True, will not use cached data.
+    no_store : bool
+        If True, will not store downloaded data.
+    data_dir : Path
+        Path to directory where data will be cached.
+    """
+
+    def __init__(
+        self,
+        leagues: Optional[Union[str, List[str]]] = None,
+        seasons: Optional[Union[str, int, Iterable[Union[str, int]]]] = None,
+        proxy: Optional[
+            Union[str, Dict[str, str], List[Dict[str, str]], Callable[[], Dict[str, str]]]
+        ] = None,
+        no_cache: bool = NOCACHE,
+        no_store: bool = NOSTORE,
+        data_dir: Path = UNDERSTAT_DATADIR,
+    ):
+        """Initialize a new Understat reader."""
+        super().__init__(
+            leagues=leagues, proxy=proxy, no_cache=no_cache, no_store=no_store, data_dir=data_dir
+        )
+        self.seasons = seasons  # type: ignore
+
+    def read_leagues(self) -> pd.DataFrame:
+        """Retrieve the selected leagues from the datasource.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        data = self._read_leagues()
+
+        leagues = {}
+
+        league_data = data["statData"]
+        for league_stat in league_data:
+            league_id = league_stat["league_id"]
+            if league_id not in leagues:
+                league = league_stat["league"]
+                league_slug = league.replace(" ", "_")
+                leagues[league_id] = {
+                    "league_id": league_id,
+                    "league": league,
+                    "url": UNDERSTAT_URL + f"/league/{league_slug}",
+                }
+
+        index = "league"
+        if len(leagues) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(list(leagues.values()))
+            .pipe(self._translate_league)
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        valid_leagues = [league for league in self.leagues if league in df.index]
+        df = df.loc[valid_leagues]
+
+        return df
+
+    def read_seasons(self) -> pd.DataFrame:
+        """Retrieve the selected seasons from the datasource.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        data = self._read_leagues()
+
+        seasons = {}
+
+        league_data = data["statData"]
+        for league_stat in league_data:
+            league_id = league_stat["league_id"]
+            year = int(league_stat["year"])
+            month = int(league_stat["month"])
+            season_id = year if month >= 7 else year - 1
+            key = (league_id, season_id)
+            if key not in seasons:
+                league = league_stat["league"]
+                league_slug = league.replace(" ", "_")
+                season = f"{season_id}/{season_id + 1}"
+                seasons[key] = {
+                    "league_id": league_id,
+                    "league": league,
+                    "season_id": season_id,
+                    "season": season_code(season),
+                    "url": UNDERSTAT_URL + f"/league/{league_slug}/{season_id}",
+                }
+
+        index = ["league", "season"]
+        if len(seasons) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(list(seasons.values()))
+            .pipe(self._translate_league)
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        all_seasons = itertools.product(self.leagues, self.seasons)
+        valid_seasons = [season for season in all_seasons if season in df.index]
+        df = df.loc[valid_seasons]
+
+        return df
+
+    def read_schedule(
+        self, include_matches_without_data: bool = True, force_cache: bool = False
+    ) -> pd.DataFrame:
+        """Retrieve the matches for the selected leagues and seasons.
+
+        Parameters
+        ----------
+        include_matches_without_data : bool
+            By default matches with and without data are returned.
+            If False, will only return matches with data.
+
+        force_cache : bool
+             By default no cached data is used for the current season.
+             If True, will force the use of cached data anyway.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        df_seasons = self.read_seasons()
+
+        matches = []
+
+        for (league, season), league_season in df_seasons.iterrows():
+            league_id = league_season["league_id"]
+            season_id = league_season["season_id"]
+            url = league_season["url"]
+
+            is_current_season = not self._is_complete(league, season)
+            no_cache = is_current_season and not force_cache
+
+            data = self._read_league_season(url, league_id, season_id, no_cache)
+
+            matches_data = data["datesData"]
+            for match in matches_data:
+                match_id = _as_int(match["id"])
+                has_home_xg = match["xG"]["h"] not in ("0", None)
+                has_away_xg = match["xG"]["a"] not in ("0", None)
+                has_data = has_home_xg or has_away_xg
+                matches.append(
+                    {
+                        "league_id": league_id,
+                        "league": league,
+                        "season_id": season_id,
+                        "season": season,
+                        "game_id": match_id,
+                        "date": match["datetime"],
+                        "home_team_id": _as_int(match["h"]["id"]),
+                        "away_team_id": _as_int(match["a"]["id"]),
+                        "home_team": _as_str(match["h"]["title"]),
+                        "away_team": _as_str(match["a"]["title"]),
+                        "away_team_code": match["a"]["short_title"],
+                        "home_team_code": match["h"]["short_title"],
+                        "home_goals": _as_int(match["goals"]["h"]),
+                        "away_goals": _as_int(match["goals"]["a"]),
+                        "home_xg": _as_float(match["xG"]["h"]),
+                        "away_xg": _as_float(match["xG"]["a"]),
+                        "is_result": _as_bool(match["isResult"]),
+                        "has_data": has_data,
+                        "url": UNDERSTAT_URL + f"/match/{match_id}",
+                    }
+                )
+
+        index = ["league", "season", "game"]
+        if len(matches) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(matches)
+            .assign(date=lambda g: pd.to_datetime(g["date"], format="%Y-%m-%d %H:%M:%S"))
+            .replace(
+                {
+                    "home_team": TEAMNAME_REPLACEMENTS,
+                    "away_team": TEAMNAME_REPLACEMENTS,
+                }
+            )
+            .assign(game=lambda g: g.apply(make_game_id, axis=1))
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        if not include_matches_without_data:
+            df = df[df["has_data"]]
+
+        return df
+
+    def read_team_match_stats(self, force_cache: bool = False) -> pd.DataFrame:
+        """Retrieve the team match stats for the selected leagues and seasons.
+
+        Parameters
+        ----------
+        force_cache : bool
+             By default no cached data is used for the current season.
+             If True, will force the use of cached data anyway.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        df_seasons = self.read_seasons()
+
+        stats = {}
+
+        for (league, season), league_season in df_seasons.iterrows():
+            league_id = league_season["league_id"]
+            season_id = league_season["season_id"]
+            url = league_season["url"]
+
+            is_current_season = not self._is_complete(league, season)
+            no_cache = is_current_season and not force_cache
+
+            data = self._read_league_season(url, league_id, season_id, no_cache)
+
+            schedule = {}
+            matches = {}
+
+            matches_data = data["datesData"]
+            for match in matches_data:
+                match_id = _as_int(match["id"])
+                match_date = match["datetime"]
+                schedule[match_id] = {
+                    "league_id": league_id,
+                    "league": league,
+                    "season_id": season_id,
+                    "season": season,
+                    "game_id": match_id,
+                    "date": match["datetime"],
+                    "home_team_id": _as_int(match["h"]["id"]),
+                    "away_team_id": _as_int(match["a"]["id"]),
+                    "home_team": _as_str(match["h"]["title"]),
+                    "away_team": _as_str(match["a"]["title"]),
+                    "away_team_code": _as_str(match["a"]["short_title"]),
+                    "home_team_code": _as_str(match["h"]["short_title"]),
+                }
+                for side in ("h", "a"):
+                    team_id = _as_int(match[side]["id"])
+                    matches[(match_date, team_id)] = match_id
+
+            teams_data = data["teamsData"]
+            for team in teams_data.values():
+                team_id = _as_int(team["id"])
+                for match in team["history"]:
+                    match_date = match["date"]
+                    match_id = matches[(match_date, team_id)]
+                    team_side = match["h_a"]
+                    if team_side == "h":
+                        prefix = "home"
+                    else:
+                        prefix = "away"
+
+                    if match_id not in stats:
+                        stats[match_id] = schedule[match_id]
+
+                    ppda = match["ppda"]
+                    team_ppda = (ppda["att"] / ppda["def"]) if ppda["def"] != 0 else pd.NA
+
+                    stats[match_id].update(
+                        {
+                            f"{prefix}_points": _as_int(match["pts"]),
+                            f"{prefix}_expected_points": _as_float(match["xpts"]),
+                            f"{prefix}_goals": _as_int(match["scored"]),
+                            f"{prefix}_xg": _as_float(match["xG"]),
+                            f"{prefix}_np_xg": _as_float(match["npxG"]),
+                            f"{prefix}_np_xg_difference": _as_float(match["npxGD"]),
+                            f"{prefix}_ppda": _as_float(team_ppda),
+                            f"{prefix}_deep_completions": _as_int(match["deep"]),
+                        }
+                    )
+
+        index = ["league", "season", "game"]
+        if len(stats) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(list(stats.values()))
+            .assign(date=lambda g: pd.to_datetime(g["date"], format="%Y-%m-%d %H:%M:%S"))
+            .replace(
+                {
+                    "home_team": TEAMNAME_REPLACEMENTS,
+                    "away_team": TEAMNAME_REPLACEMENTS,
+                }
+            )
+            .assign(game=lambda g: g.apply(make_game_id, axis=1))
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        return df
+
+    def read_player_season_stats(self, force_cache: bool = False) -> pd.DataFrame:
+        """Retrieve the player season stats for the selected leagues and seasons.
+
+        Parameters
+        ----------
+        force_cache : bool
+             By default no cached data is used for the current season.
+             If True, will force the use of cached data anyway.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        df_seasons = self.read_seasons()
+
+        stats = []
+        for (league, season), league_season in df_seasons.iterrows():
+            league_id = league_season["league_id"]
+            season_id = league_season["season_id"]
+            url = league_season["url"]
+
+            is_current_season = not self._is_complete(league, season)
+            no_cache = is_current_season and not force_cache
+
+            data = self._read_league_season(url, league_id, season_id, no_cache)
+
+            teams_data = data["teamsData"]
+            team_mapping = {}
+            for team in teams_data.values():
+                team_name = _as_str(team["title"])
+                team_id = _as_int(team["id"])
+                team_mapping[team_name] = team_id
+
+            players_data = data["playersData"]
+            for player in players_data:
+                player_team_name = player["team_title"]
+                if "," in player_team_name:  # pick first team if multiple teams are listed
+                    player_team_name = player_team_name.split(",")[0]
+                player_team_name = _as_str(player_team_name)
+                player_team_id = team_mapping[player_team_name]
+                stats.append(
+                    {
+                        "league": league,
+                        "league_id": league_id,
+                        "season": season,
+                        "season_id": season_id,
+                        "team": player_team_name,
+                        "team_id": player_team_id,
+                        "player": _as_str(player["player_name"]),
+                        "player_id": _as_int(player["id"]),
+                        "position": _as_str(player["position"]),
+                        "matches": _as_int(player["games"]),
+                        "minutes": _as_int(player["time"]),
+                        "goals": _as_int(player["goals"]),
+                        "xg": _as_float(player["xG"]),
+                        "np_goals": _as_int(player["npg"]),
+                        "np_xg": _as_float(player["npxG"]),
+                        "assists": _as_int(player["assists"]),
+                        "xa": _as_float(player["xA"]),
+                        "shots": _as_int(player["shots"]),
+                        "key_passes": _as_int(player["key_passes"]),
+                        "yellow_cards": _as_int(player["yellow_cards"]),
+                        "red_cards": _as_int(player["red_cards"]),
+                        "xg_chain": _as_float(player["xGChain"]),
+                        "xg_buildup": _as_float(player["xGBuildup"]),
+                    }
+                )
+
+        index = ["league", "season", "team", "player"]
+        if len(stats) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(stats)
+            .replace(
+                {
+                    "team": TEAMNAME_REPLACEMENTS,
+                }
+            )
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        return df
+
+    def read_player_match_stats(
+        self, match_id: Optional[Union[int, List[int]]] = None
+    ) -> pd.DataFrame:
+        """Retrieve the player match stats for the selected leagues and seasons.
+
+        Parameters
+        ----------
+        match_id : int or list of int, optional
+            Retrieve the player match stats for a specific match.
+
+        Raises
+        ------
+        ValueError
+            If the given match_id could not be found in the selected seasons.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        df_schedule = self.read_schedule(include_matches_without_data=False)
+        df_results = self._select_matches(df_schedule, match_id)
+
+        stats = []
+        for (league, season, game), league_season_game in df_results.iterrows():
+            league_id = league_season_game["league_id"]
+            season_id = league_season_game["season_id"]
+            game_id = league_season_game["game_id"]
+            url = league_season_game["url"]
+
+            data = self._read_match(url, game_id)
+            if data is None:
+                continue
+
+            match_info = data["match_info"]
+            team_id_to_name = {
+                match_info[side]: _as_str(match_info[f"team_{side}"]) for side in ("h", "a")
+            }
+
+            players_data = data["rostersData"]
+            for team_players in players_data.values():
+                for player in team_players.values():
+                    team_id = player["team_id"]
+                    team = team_id_to_name[team_id]
+                    stats.append(
+                        {
+                            "league": league,
+                            "league_id": league_id,
+                            "season": season,
+                            "season_id": season_id,
+                            "game_id": game_id,
+                            "game": game,
+                            "team": team,
+                            "team_id": _as_int(team_id),
+                            "player": _as_str(player["player"]),
+                            "player_id": _as_int(player["player_id"]),
+                            "position": _as_str(player["position"]),
+                            "position_id": _as_int(player["positionOrder"]),
+                            "minutes": _as_int(player["time"]),
+                            "goals": _as_int(player["goals"]),
+                            "own_goals": _as_int(player["own_goals"]),
+                            "shots": _as_int(player["shots"]),
+                            "xg": _as_float(player["xG"]),
+                            "xa": _as_float(player["xA"]),
+                            "xg_chain": _as_float(player["xGChain"]),
+                            "xg_buildup": _as_float(player["xGBuildup"]),
+                        }
+                    )
+
+        index = ["league", "season", "game", "team", "player"]
+        if len(stats) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(stats)
+            .replace(
+                {
+                    "team": TEAMNAME_REPLACEMENTS,
+                }
+            )
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        return df
+
+    def read_shot_events(self, match_id: Optional[Union[int, List[int]]] = None) -> pd.DataFrame:
+        """Retrieve the shot events for the selected matches or the selected leagues and seasons.
+
+        Parameters
+        ----------
+        match_id : int or list of int, optional
+            Retrieve the shot events for a specific match.
+
+        Raises
+        ------
+        ValueError
+            If the given match_id could not be found in the selected seasons.
+
+        Returns
+        -------
+        pd.DataFrame
+        """
+        df_schedule = self.read_schedule(include_matches_without_data=False)
+        df_results = self._select_matches(df_schedule, match_id)
+
+        shots = []
+        for (league, season, game), league_season_game in df_results.iterrows():
+            league_id = league_season_game["league_id"]
+            season_id = league_season_game["season_id"]
+            game_id = league_season_game["game_id"]
+            url = league_season_game["url"]
+
+            data = self._read_match(url, game_id)
+            if data is None:
+                continue
+
+            match_info = data["match_info"]
+            team_name_to_id = {
+                _as_str(match_info[f"team_{side}"]): _as_int(match_info[side])
+                for side in ("h", "a")
+            }
+
+            rosters_data = data["rostersData"]
+            player_name_to_id = {}
+            for team_data in rosters_data.values():
+                for player in team_data.values():
+                    player_name = _as_str(player["player"])
+                    player_id = _as_int(player["id"])
+                    player_name_to_id[player_name] = player_id
+
+            shots_data = data["shotsData"]
+            for team_shots in shots_data.values():
+                for shot in team_shots:
+                    team_side = shot["h_a"]
+                    team = _as_str(shot[f"{team_side}_team"])
+                    team_id = team_name_to_id[team]
+                    assist_player = _as_str(shot["player_assisted"])
+                    assist_player_id = player_name_to_id.get(assist_player, pd.NA)
+                    shots.append(
+                        {
+                            "league_id": league_id,
+                            "league": league,
+                            "season_id": season_id,
+                            "season": season,
+                            "game_id": game_id,
+                            "game": game,
+                            "date": shot["date"],
+                            "shot_id": _as_int(shot["id"]),
+                            "team_id": team_id,
+                            "team": team,
+                            "player_id": _as_int(shot["player_id"]),
+                            "player": shot["player"],
+                            "assist_player_id": assist_player_id,
+                            "assist_player": assist_player,
+                            "xg": _as_float(shot["xG"]),
+                            "location_x": _as_float(shot["X"]),
+                            "location_y": _as_float(shot["Y"]),
+                            "minute": _as_int(shot["minute"]),
+                            "body_part": SHOT_BODY_PARTS.get(shot["shotType"], pd.NA),
+                            "situation": SHOT_SITUATIONS.get(shot["situation"], pd.NA),
+                            "result": SHOT_RESULTS.get(shot["result"], pd.NA),
+                        }
+                    )
+
+        index = ["league", "season", "game", "team", "player"]
+        if len(shots) == 0:
+            return pd.DataFrame(index=index)
+
+        df = (
+            pd.DataFrame.from_records(shots)
+            .assign(date=lambda g: pd.to_datetime(g["date"], format="%Y-%m-%d %H:%M:%S"))
+            .replace(
+                {
+                    "team": TEAMNAME_REPLACEMENTS,
+                }
+            )
+            .set_index(index)
+            .sort_index()
+            .convert_dtypes()
+        )
+
+        return df
+
+    def _select_matches(
+        self, df_schedule: pd.DataFrame, match_id: Optional[Union[int, List[int]]] = None
+    ) -> pd.DataFrame:
+        if match_id is not None:
+            match_ids = [match_id] if isinstance(match_id, int) else match_id
+            df = df_schedule[df_schedule["game_id"].isin(match_ids)]
+            if df.empty:
+                raise ValueError("No matches found with the given IDs in the selected seasons.")
+        else:
+            df = df_schedule
+
+        return df
+
+    def _read_leagues(self, no_cache: bool = False) -> dict:
+        url = UNDERSTAT_URL
+        filepath = self.data_dir / "leagues.json"
+        response = self.get(url, filepath, no_cache=no_cache, var="statData")
+        data = json.load(response)
+
+        return data
+
+    def _read_league_season(
+        self, url: str, league_id: int, season_id: int, no_cache: bool = False
+    ) -> dict:
+        filepath = self.data_dir / f"league_{league_id}_season_{season_id}.json"
+        response = self.get(
+            url, filepath, no_cache=no_cache, var=["datesData", "playersData", "teamsData"]
+        )
+        data = json.load(response)
+
+        return data
+
+    def _read_match(self, url: str, match_id: int) -> Optional[dict]:
+        try:
+            filepath = self.data_dir / f"match_{match_id}.json"
+            response = self.get(url, filepath, var=["match_info", "rostersData", "shotsData"])
+            data = json.load(response)
+        except ConnectionError:
+            data = None
+
+        return data
+
+
+def _as_bool(value: Any) -> Optional[bool]:
+    try:
+        return bool(value)
+    except (TypeError, ValueError):
+        return None
+
+
+def _as_float(value: Any) -> Optional[float]:
+    try:
+        return float(value)
+    except (TypeError, ValueError):
+        return None
+
+
+def _as_int(value: Any) -> Optional[int]:
+    try:
+        return int(value)
+    except (TypeError, ValueError):
+        return None
+
+
+def _as_str(value: Any) -> Optional[str]:
+    try:
+        return unescape(value)
+    except (TypeError, ValueError):
+        return None


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 8505d394..59a5142d 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -57,3 +57,15 @@ def match_epl_2y() -> sd.MatchHistory:
 def whoscored() -> sd.WhoScored:
     """Return a correctly initialized instance of WhoScored."""
     return sd.WhoScored("ENG-Premier League", "20-21", headless=True)
+
+
+@pytest.fixture
+def understat_epl_1516() -> sd.Understat:
+    """Return a correctly initialized instance of Understat filtered by league: Premier League."""
+    return sd.Understat("ENG-Premier League", "15-16")
+
+
+@pytest.fixture
+def understat_epl_9091() -> sd.Understat:
+    """Return a correctly initialized instance of Understat filtered by league: Premier League."""
+    return sd.Understat("ENG-Premier League", "90-91")
diff --git a/tests/test_Understat.py b/tests/test_Understat.py
new file mode 100644
index 00000000..c4720b76
--- /dev/null
+++ b/tests/test_Understat.py
@@ -0,0 +1,60 @@
+"""Unittests for class soccerdata.Understat."""
+
+import pandas as pd
+import pytest
+
+from soccerdata.understat import Understat
+
+
+def test_read_leagues(understat_epl_1516: Understat) -> None:
+    leagues = understat_epl_1516.read_leagues()
+    assert isinstance(leagues, pd.DataFrame)
+    assert len(leagues) == 1
+
+
+def test_read_seasons(understat_epl_1516: Understat) -> None:
+    seasons = understat_epl_1516.read_seasons()
+    assert isinstance(seasons, pd.DataFrame)
+    assert len(seasons) == 1
+
+
+def test_read_seasons_empty(understat_epl_9091: Understat) -> None:
+    seasons = understat_epl_9091.read_seasons()
+    assert isinstance(seasons, pd.DataFrame)
+    assert len(seasons) == 0
+
+
+def test_read_schedule(understat_epl_1516: Understat) -> None:
+    schedule = understat_epl_1516.read_schedule()
+    assert isinstance(schedule, pd.DataFrame)
+    assert len(schedule) == 380
+
+
+def test_read_team_match_stats(understat_epl_1516: Understat) -> None:
+    team_match_stats = understat_epl_1516.read_team_match_stats()
+    assert isinstance(team_match_stats, pd.DataFrame)
+    assert len(team_match_stats) == 380
+
+
+def test_read_player_season_stats(understat_epl_1516: Understat) -> None:
+    player_season_stats = understat_epl_1516.read_player_season_stats()
+    assert isinstance(player_season_stats, pd.DataFrame)
+    assert len(player_season_stats) == 550
+
+
+def test_read_player_match_stats(understat_epl_1516: Understat) -> None:
+    player_match_stats = understat_epl_1516.read_player_match_stats()
+    assert isinstance(player_match_stats, pd.DataFrame)
+
+
+def test_read_shots(understat_epl_1516: Understat) -> None:
+    shots_all = understat_epl_1516.read_shot_events()
+    assert isinstance(shots_all, pd.DataFrame)
+    assert len(shots_all) == 9_819
+    shots_utd_bou = understat_epl_1516.read_shot_events(460)
+    assert isinstance(shots_utd_bou, pd.DataFrame)
+    assert len(shots_utd_bou) == 20
+    with pytest.raises(
+        ValueError, match="No matches found with the given IDs in the selected seasons."
+    ):
+        understat_epl_1516.read_shot_events(42)
diff --git a/tests/test_common.py b/tests/test_common.py
index f02801af..651abec4 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -1,6 +1,7 @@
 """Unittests for soccerdata._common."""
 
 import datetime
+import json
 
 import pandas as pd
 import pytest
@@ -59,6 +60,15 @@ def test_download_and_save_no_cache_filepath(tmp_path):
     assert not filepath.exists()
 
 
+def test_download_and_save_variable_no_store_no_filepath():
+    reader = BaseRequestsReader(no_store=True)
+    url = "https://understat.com/"
+    data = reader._download_and_save(url, filepath=None, var="statData")
+    stats = json.load(data)
+    assert isinstance(stats, dict)
+    assert "statData" in stats
+
+
 # def test_download_and_save_requests_tor(tmp_path):
 #     url = "https://check.torproject.org/api/ip"
 #     reader = BaseRequestsReader(proxy=None)