{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# TransferMarkt Historical Market Value Data Engineering\n", "##### Notebook to engineer data scraped from [TransferMarkt](https://www.transfermarkt.co.uk/) using [Beautifulsoup](https://pypi.org/project/beautifulsoup4/), the [Tyrone Mings web scraper](https://github.com/FCrSTATS/tyrone_mings) by [FCrSTATS](https://twitter.com/FC_rstats) and code from the [`football-progres-analysis`](https://github.com/Shomrey/football-progres-analysis) GitHub repo by [`Shomrey`](https://github.com/Shomrey).\n", "\n", "### By [Edd Webster](https://www.twitter.com/eddwebster)\n", "Notebook first written: 22/08/2021
\n", "Notebook last updated: 22/08/2021\n", "\n", "![title](../../img/transfermarkt-logo-banner.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## Introduction\n", "This notebook engineers previously scraped data from [TransferMarkt](https://www.transfermarkt.co.uk/) using the [FCrSTATS](https://twitter.com/FC_rstats) [Tyrone Mings webscraper](https://github.com/FCrSTATS/tyrone_mings) and manipulates this landed data as DataFrames using [pandas](http://pandas.pydata.org/) and [matplotlib](https://matplotlib.org/) for visualisation.\n", "\n", "For more information about this notebook and the author, I'm available through all the following channels:\n", "* [eddwebster.com](https://www.eddwebster.com/);\n", "* edd.j.webster@gmail.com;\n", "* [@eddwebster](https://www.twitter.com/eddwebster);\n", "* [linkedin.com/in/eddwebster](https://www.linkedin.com/in/eddwebster/);\n", "* [github/eddwebster](https://github.com/eddwebster/);\n", "* [public.tableau.com/profile/edd.webster](https://public.tableau.com/profile/edd.webster);\n", "* [kaggle.com/eddwebster](https://www.kaggle.com/eddwebster); and\n", "* [hackerrank.com/eddwebster](https://www.hackerrank.com/eddwebster).\n", "\n", "![title](../../img/fifa21eddwebsterbanner.png)\n", "\n", "The accompanying GitHub repository for this notebook can be found [here](https://github.com/eddwebster/football_analytics) and a static version of this notebook can be found [here](https://nbviewer.jupyter.org/github/eddwebster/football_analytics/blob/master/notebooks/A%29%20Web%20Scraping/TransferMarkt%20Web%20Scraping%20and%20Parsing.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## Notebook Contents\n", "1. [Notebook Dependencies](#section1)
\n", "2. [Project Brief](#section2)
\n", "3. [Data Sources](#section3)
\n", " 1. [Introduction](#section3.1)
\n", " 2. [Data Dictionary](#section3.2)
\n", " 3. [Creating the DataFrame](#section3.3)
\n", " 4. [Initial Data Handling](#section3.4)
\n", " 5. [Export the Raw DataFrame](#section3.5)
\n", "4. [Data Engineering](#section4)
\n", " 1. [Introduction](#section4.1)
\n", " 2. [Columns of Interest](#section4.2)
\n", " 3. [String Cleaning](#section4.3)
\n", " 4. [Converting Data Types](#section4.4)
\n", " 5. [Export the Engineered DataFrame](#section4.5)
\n", "5. [Exploratory Data Analysis (EDA)](#section5)
\n", " 1. [...](#section5.1)
\n", " 2. [...](#section5.2)
\n", " 3. [...](#section5.3)
\n", "6. [Summary](#section6)
\n", "7. [Next Steps](#section7)
\n", "8. [Bibliography](#section8)
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 1. Notebook Dependencies\n", "This notebook was written using [Python 3](https://docs.python.org/3.7/) and requires the following libraries:\n", "* [`Jupyter notebooks`](https://jupyter.org/) for this notebook environment with which this project is presented;\n", "* [`NumPy`](http://www.numpy.org/) for multidimensional array computing;\n", "* [`pandas`](http://pandas.pydata.org/) for data analysis and manipulation; and\n", "* [`matplotlib`](https://matplotlib.org/contents.html?v=20200411155018) for data visualisations.\n", "\n", "All packages used for this notebook except for BeautifulSoup can be obtained by downloading and installing the [Conda](https://anaconda.org/anaconda/conda) distribution, available on all platforms (Windows, Linux and Mac OSX). Step-by-step guides on how to install Anaconda can be found for Windows [here](https://medium.com/@GalarnykMichael/install-python-on-windows-anaconda-c63c7c3d1444) and Mac [here](https://medium.com/@GalarnykMichael/install-python-on-mac-anaconda-ccd9f2014072), as well as in the Anaconda documentation itself [here](https://docs.anaconda.com/anaconda/install/)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Import Libraries and Modules" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Setup Complete\n" ] } ], "source": [ "# Python ≥3.5 (ideally)\n", "import platform\n", "import sys, getopt\n", "assert sys.version_info >= (3, 5)\n", "import csv\n", "\n", "# Import Dependencies\n", "%matplotlib inline\n", "\n", "# Math Operations\n", "import numpy as np\n", "import math\n", "from math import pi\n", "\n", "# Datetime\n", "import datetime\n", "from datetime import date\n", "import time\n", "\n", "# Data Preprocessing\n", "import pandas as pd\n", "import os\n", "import re\n", "import random\n", "from io import BytesIO\n", "from pathlib import Path\n", "\n", "# Reading directories\n", "import glob\n", "import os\n", "from os.path import basename\n", "\n", "# Flatten lists\n", "from functools import reduce\n", "\n", "# Working with JSON\n", "import json\n", "from pandas.io.json import json_normalize\n", "\n", "# Web Scraping\n", "import requests\n", "from bs4 import BeautifulSoup\n", "import re\n", "\n", "# Currency Converter\n", "from currency_converter import CurrencyConverter\n", "\n", "# APIs\n", "from tyrone_mings import * \n", "\n", "# Fuzzy Matching - Record Linkage\n", "import recordlinkage\n", "import jellyfish\n", "import numexpr as ne\n", "\n", "# Data Visualisation\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "plt.style.use('seaborn-whitegrid')\n", "import missingno as msno\n", "\n", "# Progress Bar\n", "from tqdm import tqdm\n", "\n", "# Display in Jupyter\n", "from IPython.display import Image, YouTubeVideo\n", "from IPython.core.display import HTML\n", "\n", "# Ignore Warnings\n", "import warnings\n", "warnings.filterwarnings(action=\"ignore\", message=\"^internal gelsd\")\n", "\n", "print('Setup Complete')" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Python: 3.7.6\n", "NumPy: 1.20.3\n", "pandas: 1.3.2\n", "matplotlib: 3.4.2\n" ] } ], "source": [ "# Python / module versions used here for reference\n", "print('Python: {}'.format(platform.python_version()))\n", "print('NumPy: {}'.format(np.__version__))\n", "print('pandas: {}'.format(pd.__version__))\n", "print('matplotlib: {}'.format(mpl.__version__))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Defined Filepaths" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Set up initial paths to subfolders\n", "base_dir = os.path.join('..', '..')\n", "data_dir = os.path.join(base_dir, 'data')\n", "data_dir_tm = os.path.join(base_dir, 'data', 'tm')\n", "img_dir = os.path.join(base_dir, 'img')\n", "fig_dir = os.path.join(base_dir, 'img', 'fig')\n", "video_dir = os.path.join(base_dir, 'video')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Defined Variables" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Defined Variables\n", "\n", "## Define today's date\n", "today = datetime.datetime.now().strftime('%d/%m/%Y').replace('/', '')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Defined Dictionaries" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [], "source": [ "# Defined Dictionaries\n", "\n", "## Define seasons\n", "dict_seasons = {'2000': '2000/2001',\n", " '2001': '2001/2002',\n", " '2002': '2002/2003',\n", " '2003': '2003/2004',\n", " '2004': '2004/2005',\n", " '2005': '2005/2006',\n", " '2006': '2006/2007',\n", " '2007': '2007/2008',\n", " '2008': '2008/2009',\n", " '2009': '2009/2010',\n", " '2010': '2010/2011',\n", " '2011': '2011/2012',\n", " '2012': '2012/2013',\n", " '2013': '2013/2014',\n", " '2014': '2014/2015',\n", " '2015': '2015/2016',\n", " '2016': '2016/2017',\n", " '2017': '2017/2018',\n", " '2018': '2018/2019',\n", " '2019': '2019/2020',\n", " '2020': '2020/2021',\n", " '2021': '2021/2022',\n", " '2022': '2022/2023',\n", " '2023': '2023/2024',\n", " }" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Defined Lists" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Defined Lists\n", "\n", "## Define list of league codes\n", "df_leagues = pd.read_csv(data_dir_tm + '/reference/tm_leagues_comps.csv')\n", "lst_league_codes = df_leagues['league_code'].to_numpy().tolist()\n", "\n", "## Define list of 'Big 5' European Leagues and MLS codes\n", "lst_big5_mls_league_codes = ['GB1', 'FR1', 'L1', 'IT1', 'ES1', 'MLS1']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Notebook Settings" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "pd.set_option('display.max_columns', None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "\n", "\n", "## 2. Project Brief\n", "This Jupyter notebook is part of a series of notebooks to scrape, parse, engineer, unify, and the model, culminating in a an Expected Transfer (xTransfer) player performance vs. valuation model. This model aims to determine the under- and over-performing players based on their on-the-pitch output against transfer fee and wages.\n", "\n", "This particular notebook is one of several data eningeering notebooks, that cleans player valuation data from [TransferMarkt](https://www.transfermarkt.co.uk/) using [pandas](http://pandas.pydata.org/).\n", "\n", "[TransferMarkt](https://www.transfermarkt.co.uk/) is a German-based website owned by [Axel Springer](https://www.axelspringer.com/en/) and is the leading website for the football transfer market. The website posts football related data, including: scores and results, football news, transfer rumours, and most usefully for us - calculated estimates ofthe market values for teams and individual players.\n", "\n", "To read more about how these estimations are made, [Beyond crowd judgments: Data-driven estimation of market value in association football](https://www.sciencedirect.com/science/article/pii/S0377221717304332) by Oliver Müllera, Alexander Simons, and Markus Weinmann does an excellent job of explaining how the estimations are made and their level of accuracy.\n", "\n", "This notebook, along with the other notebooks in this project workflow are shown in the following diagram:\n", "\n", "![roadmap](../../img/football_analytics_data_roadmap.png)\n", "\n", "Links to these notebooks in the [`football_analytics`](https://github.com/eddwebster/football_analytics) GitHub repository can be found at the following:\n", "* [Webscraping](https://github.com/eddwebster/football_analytics/tree/master/notebooks/1_data_scraping)\n", " + [FBref Player Stats Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/FBref%20Player%20Stats%20Web%20Scraping.ipynb)\n", " + [TransferMarket Player Bio and Status Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/TransferMarkt%20Player%20Bio%20and%20Status%20Web%20Scraping.ipynb)\n", " + [TransferMarket Player Valuation Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/TransferMarkt%20Player%20Valuation%20Web%20Scraping.ipynb)\n", " + [TransferMarkt Player Recorded Transfer Fees Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/TransferMarkt%20Player%20Recorded%20Transfer%20Fees%20Webscraping.ipynb)\n", " + [Capology Player Salary Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/Capology%20Player%20Salary%20Web%20Scraping.ipynb)\n", " + [FBref Team Stats Webscraping](https://github.com/eddwebster/football_analytics/blob/master/notebooks/1_data_scraping/FBref%20Team%20Stats%20Web%20Scraping.ipynb)\n", "* [Data Parsing](https://github.com/eddwebster/football_analytics/tree/master/notebooks/2_data_parsing)\n", " + [ELO Team Ratings Data Parsing](https://github.com/eddwebster/football_analytics/blob/master/notebooks/2_data_parsing/ELO%20Team%20Ratings%20Data%20Parsing.ipynb)\n", "* [Data Engineering](https://github.com/eddwebster/football_analytics/tree/master/notebooks/3_data_engineering)\n", " + [FBref Player Stats Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/FBref%20Player%20Stats%20Data%20Engineering.ipynb)\n", " + [TransferMarket Player Bio and Status Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/TransferMarkt%20Player%20Bio%20and%20Status%20Data%20Engineering.ipynb)\n", " + [TransferMarket Player Valuation Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/TransferMarkt%20Player%20Valuation%20Data%20Engineering.ipynb)\n", " + [TransferMarkt Player Recorded Transfer Fees Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/TransferMarkt%20Player%20Recorded%20Transfer%20Fees%20Data%20Engineering.ipynb)\n", " + [Capology Player Salary Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/Capology%20Player%20Salary%20Data%20Engineering.ipynb)\n", " + [FBref Team Stats Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/FBref%20Team%20Stats%20Data%20Engineering.ipynb)\n", " + [ELO Team Ratings Data Parsing](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/ELO%20Team%20Ratings%20Data%20Parsing.ipynb)\n", " + [TransferMarkt Team Recorded Transfer Fee Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/TransferMarkt%20Team%20Recorded%20Transfer%20Fee%20Data%20Engineering.ipynb) (aggregated from [TransferMarkt Player Recorded Transfer Fees notebook](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/TransferMarkt%20Player%20Recorded%20Transfer%20Fees%20Data%20Engineering.ipynb))\n", " + [Capology Team Salary Data Engineering](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/Capology%20Team%20Salary%20Data%20Engineering.ipynb) (aggregated from [Capology Player Salary notebook](https://github.com/eddwebster/football_analytics/blob/master/notebooks/3_data_engineering/Capology%20Player%20Salary%20Data%20Engineering.ipynb))\n", "* [Data Unification](https://github.com/eddwebster/football_analytics/tree/master/notebooks/4_data_unification)\n", " + [Golden ID for Player Level Datasets](https://github.com/eddwebster/football_analytics/blob/master/notebooks/4_data_unification/Golden%20ID%20for%20Player%20Level%20Datasets.ipynb)\n", " + [Golden ID for Team Level Datasets](https://github.com/eddwebster/football_analytics/blob/master/notebooks/4_data_unification/Golden%20ID%20for%20Team%20Level%20Datasets.ipynb)\n", "* [Production Datasets](https://github.com/eddwebster/football_analytics/tree/master/notebooks/5_production_datasets)\n", " + [Player Performance/Market Value Dataset](https://github.com/eddwebster/football_analytics/tree/master/notebooks/5_production_datasets/Player%20Performance/Market%20Value%20Dataset.ipynb)\n", " + [Team Performance/Market Value Dataset](https://github.com/eddwebster/football_analytics/tree/master/notebooks/5_production_datasets/Team%20Performance/Market%20Value%20Dataset.ipynb)\n", "* [Expected Transfer (xTransfer) Modeling](https://github.com/eddwebster/football_analytics/tree/master/notebooks/6_data_analysis_and_projects/expected_transfer_modeling)\n", " + [Expected Transfer (xTransfer) Modeling](https://github.com/eddwebster/football_analytics/tree/master/notebooks/6_data_analysis_and_projects/expected_transfer_modeling/Expected%20Transfer%20%20Modeling.ipynb)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "\n", "\n", "## 3. Data Sources" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "### 3.1. Introduction\n", "Before conducting our EDA, the data needs to be imported as a DataFrame in the Data Sources section [Section 3](#section3) and cleaned in the Data Engineering section [Section 4](#section4).\n", "\n", "We'll be using the [pandas](http://pandas.pydata.org/) library to import our data to this workbook as a DataFrame." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2. Data Dictionaries\n", "The [TransferMarkt](https://www.transfermarkt.co.uk/) dataset has six features (columns) with the following definitions and data types:\n", "\n", "| Feature | Data type |\n", "|------|-----|\n", "| `position_number` | object |\n", "| `position_description` | object |\n", "| `name` | object |\n", "| `dob` | object |\n", "| `nationality` | object |\n", "| `value` | object |" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "### 3.3. Read in Data" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# Import DataFrame as a CSV file\n", "df_tm_market_value_raw = pd.read_csv(data_dir_tm + f'/raw/historical_market_values/tm_player_valuations_combined_latest.csv')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 3.2.3. Preliminary Data Handling\n", "Let's quality of the dataset by looking first and last rows in pandas using the [head()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.head.html) and [tail()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.tail.html) methods." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
market_valueclubdatetm_idleague_codeseason
050000sc Heerenveen Emmen IIOct 31, 200872462GB12017
1200000sc Heerenveen Emmen IIMay 25, 200972462GB12017
2500000SC HeerenveenJan 17, 201172462GB12017
31000000SC HeerenveenJun 28, 201172462GB12017
42000000SC HeerenveenOct 21, 201172462GB12017
\n", "
" ], "text/plain": [ " market_value club date tm_id league_code \\\n", "0 50000 sc Heerenveen Emmen II Oct 31, 2008 72462 GB1 \n", "1 200000 sc Heerenveen Emmen II May 25, 2009 72462 GB1 \n", "2 500000 SC Heerenveen Jan 17, 2011 72462 GB1 \n", "3 1000000 SC Heerenveen Jun 28, 2011 72462 GB1 \n", "4 2000000 SC Heerenveen Oct 21, 2011 72462 GB1 \n", "\n", " season \n", "0 2017 \n", "1 2017 \n", "2 2017 \n", "3 2017 \n", "4 2017 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Display the first five rows of the raw DataFrame, df_tm_market_value_raw\n", "df_tm_market_value_raw.head()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
market_valueclubdatetm_idleague_codeseason
3939484500000TSG 1899 HoffenheimApr 8, 202068033L12016
3939493000000Eintracht FrankfurtSep 16, 202068033L12016
3939502500000Eintracht FrankfurtFeb 10, 202168033L12016
3939512500000Eintracht FrankfurtMay 25, 202168033L12016
3939523500000Eintracht FrankfurtJul 15, 202168033L12016
\n", "
" ], "text/plain": [ " market_value club date tm_id league_code \\\n", "393948 4500000 TSG 1899 Hoffenheim Apr 8, 2020 68033 L1 \n", "393949 3000000 Eintracht Frankfurt Sep 16, 2020 68033 L1 \n", "393950 2500000 Eintracht Frankfurt Feb 10, 2021 68033 L1 \n", "393951 2500000 Eintracht Frankfurt May 25, 2021 68033 L1 \n", "393952 3500000 Eintracht Frankfurt Jul 15, 2021 68033 L1 \n", "\n", " season \n", "393948 2016 \n", "393949 2016 \n", "393950 2016 \n", "393951 2016 \n", "393952 2016 " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Display the last five rows of the raw DataFrame, df_tm_market_value_raw\n", "df_tm_market_value_raw.tail()" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(393953, 6)\n" ] } ], "source": [ "# Print the shape of the raw DataFrame, df_tm_market_value_raw\n", "print(df_tm_market_value_raw.shape)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Index(['market_value', 'club', 'date', 'tm_id', 'league_code', 'season'], dtype='object')\n" ] } ], "source": [ "# Print the column names of the raw DataFrame, df_tm_market_value_raw\n", "print(df_tm_market_value_raw.columns)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The dataset has thirteen features (columns). Full details of these attributes can be found in the [Data Dictionary](section3.3.1)." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "market_value int64\n", "club object\n", "date object\n", "tm_id int64\n", "league_code object\n", "season int64\n", "dtype: object" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Data types of the features of the raw DataFrame, df_tm_market_value_raw\n", "df_tm_market_value_raw.dtypes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All thirteen of the columns have the object data type. Full details of these attributes and their data types can be found in the [Data Dictionary](section3.3.1)." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 393953 entries, 0 to 393952\n", "Data columns (total 6 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 market_value 393953 non-null int64 \n", " 1 club 393953 non-null object\n", " 2 date 389883 non-null object\n", " 3 tm_id 393953 non-null int64 \n", " 4 league_code 393953 non-null object\n", " 5 season 393953 non-null int64 \n", "dtypes: int64(3), object(3)\n", "memory usage: 18.0+ MB\n" ] } ], "source": [ "# Info for the raw DataFrame, df_tm_market_value_raw\n", "df_tm_market_value_raw.info()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
market_valuetm_idseason
count3.939530e+05393953.000000393953.000000
mean6.291314e+06168284.1484062018.188045
std1.206654e+07137133.7749561.642296
min0.000000e+0026.0000002016.000000
25%5.000000e+0557135.0000002017.000000
50%2.000000e+06128969.0000002018.000000
75%6.500000e+06249730.0000002020.000000
max2.000000e+08921655.0000002021.000000
\n", "
" ], "text/plain": [ " market_value tm_id season\n", "count 3.939530e+05 393953.000000 393953.000000\n", "mean 6.291314e+06 168284.148406 2018.188045\n", "std 1.206654e+07 137133.774956 1.642296\n", "min 0.000000e+00 26.000000 2016.000000\n", "25% 5.000000e+05 57135.000000 2017.000000\n", "50% 2.000000e+06 128969.000000 2018.000000\n", "75% 6.500000e+06 249730.000000 2020.000000\n", "max 2.000000e+08 921655.000000 2021.000000" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Description of the raw DataFrame, df_tm_market_value_raw, showing some summary statistics for each numberical column in the DataFrame\n", "df_tm_market_value_raw.describe()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABuYAAAHoCAYAAAC1olk8AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAABXjklEQVR4nO3dd+Bd8+H/8dfNZyQyZIhEEhEaUS2tUfpFtSgxKwixQoaVKiERe4QgYkYIYpdIULRGjRolvrRGa7VqxBYhkSHI/MzfH/3l85VS1ZbzSXg8/iH3c+/xvh+ue855nvN+l+rr6+sDAAAAAAAAfKWaNPYAAAAAAAAA4JtAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIc8C/pba2trGHAAAAAAAAy6Tyxh4AsOyoqalJeXl5FixYkNtuuy0zZszI8ssvn0022SQ9evRIqVRq7CECAAAAAMBSq1RfX1/f2IMAln719fUplUqZO3du+vTpk7q6ulRUVGTatGnp3LlzNt988wwZMiRNmrgRFwAAAAAAPosz6MAXUiqVUldXl+HDh6dt27a57LLLcvvtt+fPf/5zampq8utf/zovvvhiYw8TAAAAvnH+2bITdXV1BY8EAPhXhDngC6uvr89bb72VDTfcMF27dk1ZWVkmTZqU119/PcOGDcvMmTPzxBNPNPYwAQAA4BujpqYmZWVlWbRoUR5//PHcfffd+dOf/pQkZrUBgKWQNeaAf6q2tjZlZWUNf/7444/zzjvvpLy8PGVlZbnzzjtz5JFH5rDDDkvv3r2z3377pWPHjvmf//mfRhw1AAAAfDPU1dWlvLw8c+fOTd++fbNw4cK88847adu2bbp06ZLTTz89q6++ujXhAWApIswB/1RZWVkWLFiQZ599Nuuuu27atGmTLbbYIr///e+TJJdcckmGDh2a/fffP8nfp7tcsGBBYw4ZAAAAvvbq6urSpEmTNGnSJNXV1Rk8eHBatWqVU089Ne3bt8/MmTPTr1+/HH/88bn00kuzwgorNKwdDwA0LvezA59r5MiRGThwYB555JEkyXbbbZeZM2fm4osvzl577ZVBgwalrKwsU6ZMybvvvpvu3bs38ogBAADg6+n111/Pe++9lyZNmjSsKzdt2rS8++672X333bPOOuukS5cueeutt1JTU5Pdd989kydPzoIFC0Q5AFhKuGMO+FzDhw/PO++8k5NPPjmlUik9e/bMUUcdlXPOOSd/+9vfcs0112TBggV54IEH0qxZsxx88MGNPWQAAAD42pk9e3aGDRuWurq6XHrppenUqVOSZNGiRZk5c2bDUhR33nlnjj766BxxxBH56U9/miFDhmSjjTbKIYcc0pjDBwD+P3fMAQ2qq6s/9efKyspcccUVWX311XPiiSfm/vvvz0477ZTTTjst3bp1yyWXXJKHH3443/rWt3LzzTenvLy84ao9AAAA4MvRrl279OrVK3V1dTnyyCMzderUJEnLli3TrFmzPP/887njjjty5JFHZujQoTnooIPSpEmTvPPOO6mqqmrk0QMAi7ljDr7hpk2bliRZaaWVUlFRkXnz5uX888/P8ccfn4qKitTU1KSioiJXX3119ttvv5x00klJkp49e2aLLbbI7Nmz06pVq1RUVCRJampqUl7ufy0AAADwZVm8ptzAgQNTWVmZ22+/Pcccc0zOOeecdOrUKQcffHDOPPPM1NTU5JhjjsnAgQOTJDNnzsxyyy2XLl26JIl15gBgKeCOOfiGqq+vz/vvv5+tttoql1xySd57770kyZ/+9KdMmDAhgwcPTl1dXcrLyxvi3GWXXZaVV145Z511Vu69997Mmzcv7dq1a4hy9fX1ohwAAAB8yerr65P8PdAlSZMmTfLnP/85xx57bKZNm5a+fftm4MCBKS8vz/vvv58//vGPueeee3LCCSekefPm2XXXXZNElAOApUCpfvE3O/CNdP755+fyyy9Pv379csABB6Rdu3a56667MmLEiGy44Ya55JJL0qRJk1RXV6eioiI33XRThg8fnhVWWCHnnXdeNtpoo8Z+CwAAAPC1N3/+/Oy4447p3LlzunTpkjlz5uTZZ59N9+7dM3r06LRv3z4TJkzIpZdemrq6urRr1y6rrLJKLrroolRUVKS2trZhHToAoPEIc/ANtXgajCS55JJLcuGFF6Zfv3456KCDssIKK+T222/Pqaeemh/+8Ie5+OKLG3beJ06cmDfeeCOtWrXKoYceaqceAAAAvkKLp5+88sorc9ttt2XcuHHp2rVrkuS2227LjTfemLKyspx33nlZaaWVMnXq1MybNy9NmzbNKqusklKpZNkJAFiK+EaGb6gmTZo07Jj/4he/SH19fcaOHZskGTRoUHbaaackyWmnnZZDDz00Q4cOzfz583PnnXdm0003zSGHHJIkrrgDAACAr9Di6SfnzJmT6urqtG3btuFnO++8c0qlUs4+++wce+yxGTVqVMN6costXqYCAFg6+FaGb6DFMe2TO+aHHHJI6urqcvHFFyf5vzjXpEmTnHXWWenVq1eWX375dOnSJQcddFDD60Q5AAAA+HItvksuScNFtRUVFZk3b15mz56dli1bNhzb77TTTnnggQdy//33Z//9988111yTDh06NGxr8Ww5AMDSQZiDb5jFO/QLFizIFVdckdra2nTp0iW77757Bg8enCQNce6ggw5Kr1698qMf/Si/+93v0rp162y33XYpKyszDQYAAAB8BRYHt8VxbtGiRSkvL8++++6bm2++OWeddVYuuuiiJS6Ubdu2bdZff/2su+66WWGFFRpx9ADAv2KNOfgGWbyu3Ny5c7PHHntk/vz5WbBgQSorK9OzZ8+cdNJJSZKxY8fm4osvTv/+/dOvX79PTYNh+koAAAD48i0+3p43b17OO++8vPbaa5k3b14222yz7LzzznnuuecyYsSIbLjhhhk6dGjat2+fWbNm5cQTT8xPf/rTHHjggSmVSo7bAWApJszBN0xVVVX69euXZs2a5aSTTkrz5s1z4okn5tlnn81OO+2U4cOHJ/m/ONe7d+8cccQRad++fSOPHAAAAL7+5s+fnz59+qR58+ZZeeWVU1lZmdtvvz3/8z//k/79+2fhwoUZNWpUqqurU15enhYtWqSysjK33nprysvLl5gGEwBY+piHDr4hFu+YP/XUU/n4448zfPjwdO/ePTNmzEjLli2z2mqr5f7770+pVMpJJ52UwYMHZ/78+Xn66afTrl27xh4+AAAAfCNceeWVadasWc4555ysuuqqSZJ99tknBxxwQCZMmJBRo0bl7rvvzq233pqqqqq0bds2O++8c8rKytwpBwDLAGEOvuYW75TX1dWlrKwsc+bMyaxZs1JZWZkkufbaa/Pee+/lyCOPzA033JCJEyemSZMmOeqoo3LMMcc0BL3F02ACAAAAX52XX345nTp1aohy1dXV+d73vpfLL788e+yxR37961/nF7/4Rfr167fE60Q5AFg2OMsOX3NlZWVZuHBhTjnllLzxxhvp3r17Vltttay00kq55557ctVVV+Wwww7LRhttlN69eydJrrvuuob15pK/320nygEAAMCXq66ubok/19TUpLq6OgsWLEhVVVWSpKKiItXV1VlnnXWy/fbb5/e//33mz5+fmpqaJV4rygHAssGZdvgGeOaZZ3LzzTfnxRdfzBprrJELLrggLVu2zG9+85vssssu2XTTTVNVVZXJkydn/fXXz/XXX58zzjgjSVIqlcxNDwAAAF+ympqaNGnSJNXV1ZkyZUqmTp2aUqmUTTfdNE888UQef/zxhudWVFQ0vKZdu3Zp3rx5ystNhAUAyyJhDr4BNt544+y6664ZPXp05syZkw4dOmT+/PmZPn16w51w7733Xv73f/833/nOd7L++us3zE0PAAAAfLlqa2tTXl6euXPnZtCgQTnggAOy2267Zfjw4dl1112z3nrr5YQTTsjDDz+cRYsWJUleffXVvPPOO+nRo0cjjx4A+G+U6uvr6xt7EMCX5x/nlK+urk5FRUUee+yxnHbaaTnwwAOzyy67JEkuuuiiXHTRRVlrrbUye/bstG7dOrfcckvKy8sb1pYDAAAAvnyLFi3KXnvtlVatWmXPPffM9OnT8+1vfzsbb7xx3n777YwYMSJ//OMf88Mf/jDNmzfPW2+9lcrKSsftALCME+bga2jBggU5//zzs++++6Zz584NoW7//ffP3Llz86tf/SpJMn369DzwwAN55pln0qVLlwwePDjl5eUWjAYAAICv2KOPPprTTjstZ555ZtZbb70lfjZ9+vRUVFTk3nvvzaRJk1IqldKjR48cfvjhjtsBYBknzMHX0I033pixY8dm0aJF6dOnT37yk59k4403zuuvv57+/ftn//33z4ABAxqeX1dX1zClZU1NjXnqAQAA4Ct2yy235KSTTsojjzyS9u3bN8S2hQsX5pprrslDDz2UG264IXV1dUscpztuB4BlmzXm4GuoT58+ufvuuzNw4MA8/vjjOeyww3L66afnvffey6abbppXX301H3/8cerr61NfX98Q5ZLYuQcAAIACrLTSSmndunUefvjhVFdXp6ysLPX19WnWrFmWW265vPfee/noo48+dZzuuB0Alm2+yeFrpr6+PmVlZWndunUOOeSQbLfddnnmmWcyduzYvPbaa3nrrbcye/bsbLPNNvnxj3/c2MMFAACAb6QNN9wwnTp1yi9/+ct861vfytprr52KiookSdu2bbPCCiuktra2kUcJAHzZ3DEHXzOLF36uq6tLknzrW9/KrrvumptuuinbbLNNvvOd72ThwoW5++67G3OYAAAA8I1VW1ubpk2b5pJLLsm8efNy0kkn5fbbb8/06dPz5z//Oddff326dOmSdu3aNfZQAYAvmTXm4Bvgk2vIJckdd9yRHXbYwULRAAAA0EgWH6tPnTo1hxxySMPUlSuvvHLatm2biRMnpqKi4lPH9ADAsk2Yg2VIVVVVKisrk/x9ysrFd8d9Uf+4M2/BaAAAAGg8i4/Tq6qq8tRTT2X69Onp2LFjfvjDH6asrMxxOyxj/pPzdcA3jzAHy4gZM2bkpptuSq9evdK1a1df9AAAAPA1UFtb+5kz2vyzx4Glz8yZM7P88ss3XFAP8HncBw/LiPLy8txxxx05/fTT88Ybb+Skk07Ka6+99oVfr8EDAADA0mdxfFu8Vvw/Pg4s3U477bQcdNBB2W233fLrX/86s2fPbuwhAUs5YQ6WEW3atMnIkSPz7LPPZuedd86UKVOy4oorfqHXfvLuuuuvvz6TJk36CkcKAAAA3zy1tbX/9Gf/6mLZ+vr6hqUn3n777SxcuPBLHRvw1TjqqKNy77335vvf/35atGiRU089NTfeeGNmzZrV2EMDlmImqYZlRKlUytprr51SqZRFixalrq4uixYt+pev+2SUmzhxYk477bSMGjXqqx4uAAAAfGMsXgtuwYIFufPOOzN79uwst9xy2WabbdK+ffuUlZV9at33xT553H7VVVflzjvvzNixY7PyyisX/TaAf8PHH3+cRYsW5ZxzzsnGG2+cJBk+fHiuuuqq1NXVZa+99soKK6zQyKMElkbCHCzlFl9VVyqVsmDBggwbNiyVlZU544wzctxxx2XkyJHp2LHjP33t4p376667LmeccUZOP/307LLLLoWNHwAAAL7O6uvrU15enrlz56ZPnz6pr69PbW1tPvzww9xwww3Zdddd07dv3yy33HKf+dpPHrefd955OeGEE0Q5WMqdc845uf7669OuXbsl4tupp56aJPnlL3+ZJOIc8JlMZQlLsZqamoYd9CRp3bp1+vTpk5122ilnn312/vrXv+b444/P9OnTP/Xa2traT0W5U089Nbvttlth4wcAgG+af1wjCvj6K5VKqa2tzfHHH5/WrVtn3LhxufXWW/Pkk09m/vz5uemmm/L2229/ajrLz7qYdsSIEenbt29jvA3g39CzZ89897vfzfTp0zNjxowk/7cPcOqpp2aHHXbIddddl6uvvtqac8CnCHOwlKqtrU15eXnmzZuX448/Pv369UuvXr0yduzYvPDCC9lss81y9tln5/nnn8/w4cMzbdq0TJ8+PS+99FKS/1sk+pNRrk+fPo35lgAA4Gvr9ddfb5im7vPWmQK+nqqrq/POO+/kJz/5SVZdddW0bNkyDz/8cKZPn55BgwZl2rRp+dvf/tbw/M+Kco7bYdmx7rrr5sQTT0y3bt0ycuTIvPrqq2nSpMkSce7HP/5x7rrrrkYeKbA0KtX/q9VngUYzf/789O7dO8svv3zWWWedLFy4MM8++2w+/vjjjBo1KhtvvHEefvjhHH300WnXrl3q6uqy9tpr59xzz02pVMp1112XM888M6eccoqdewAA+IrMnj07ffr0SatWrfKb3/ymIc4tvlgO+Pr5x8/4nDlzss0222SfffbJ4MGDc/fdd+eII47I4YcfnoMPPjgDBw5Mp06dcsYZZ4hysIy69957884776SioiLdu3fPj370o7z44os54ogjUlZWljFjxmT11VdfYj3JGTNmZMUVV2zkkQNLG2vMwVJswoQJKS8vz7nnnpuuXbumVCrl9NNPz4QJEzJ37tx8/PHH2WyzzXLJJZfk6quvTmVlZc4666yUSqU88MADGTlyZE477TQ79wAA8BVq0aJFBgwYkCuvvDL9+vXL+PHjU1ZWJs7B11hZWVkWLFiQV155JWuttVZat26d//mf/8kTTzyR8vLyXHDBBTniiCOy//77J/l7yKuqqkqShih3+eWXZ+zYsaIcLAMOP/zw/PnPf07Tpk0zb968zJ07N/vss0+OO+64jB49OkOGDMnQoUMzZsyYdO/evSHOiXLAZzGVJSxF/vEG1nfffTfNmzdPp06dUiqVcvfdd2fChAk54YQTUllZmcsvvzxz587ND37wg1x88cU5//zzU15enurq6nTt2jWXX365nXsAAPgK1dfXp2nTptl3331zyCGH5P3338/AgQNTV1fXEOeAr6dRo0Zl9913z5/+9KeUSqXstNNOeeaZZ3LBBRdkwIABOeigg1JWVpYpU6Zk5syZWW211ZL8fR2quXPnZvz48TnmmGMct8NS7vLLL8+LL76Yc889N7/73e9yyy235NBDD83EiRNz+umn5zvf+U7GjBmTJBkwYEBef/31hjvmAD6L/0PAUqK2tjalUinV1dUNj5WVlWXmzJmpqKjI73//+xxxxBEZOnRo9t1337z11lv51a9+lTlz5iyxnbq6ulRUVOTb3/52fvKTnxT8LgAA4Jtl8Voy9fX1mTt3brp06ZInnngigwYNEufga+6QQw7JJptskmHDhuWxxx7LlltumTPPPDNNmjTJK6+8kmuuuSa//OUvc/jhh6dp06YZNGhQw2tbtmyZe++9N/vss08jvgPgi3juueey/vrrZ8MNN0xlZWW6du2affbZJ0ceeWQmTJiQ2267Ld/5zndy+umnp1OnTqmoqGjsIQNLOWEOlgL19fUN02AMGDAgf/nLX5IkW265Zaqqqhquvj3mmGOy3377JUlqamqy0korpXnz5ktsyxU5AABQnLKyssyfPz/bbLNNHnzwway00kr54Q9/mCeffDL77LOPOAdfEzU1NUv8uba2Nh07dsyZZ56Z1VdfPUcccUQee+yx7LjjjrngggvSrFmzjBs3Lvfcc09WXXXV3HzzzSkvL09tbW3DcXuLFi0a460AX1BNTU3mzp2byZMnp0WLFikvL2+YkrZVq1bZbrvt0qNHjzz11FNJku9///uZMGFCunbt2pjDBpYBzuBDI3n++edz2mmnJfm/+eX/+te/5plnnsnKK6+cJFlnnXXy05/+NC+88EJ+8IMfZODAgamoqMiUKVNyzz33ZLXVVkvbtm0b7T0AAMA3zcyZMz81Bf3111+fysrKjBw5MqNGjcr48eMzatSozJo1S5yDr4ny8vIsWLAgp59+epI0fKY7dOiQc845J2ussUbDnXM9e/bMBRdckHvuuSfXXHNNRo8enfLy8tTU1Fh3EpYh5eXladmyZTbccMPcddddmTFjRiorKxviXMeOHbPiiivm3XffTV1dXUqlUiorKxt51MCyQJiDRlBXV5dnn302EydOzIgRI5b4WdOmTRv+vkWLFhk6dGi22267vPfee9lxxx0zcODADBo0KDU1NTnvvPNSKpU+dWIAAAD48r311lv56U9/mmeffXaJx6dNm5ba2tqGC+ySpGfPnhkyZEheeumlDBo0qGGWjMVTXwLLhk9+Zh988MFMmDAhBx98cJIl49yoUaPSqVOnDB8+PI8//niSpF27dg2z3NTX16e8vLz4NwD822677bZcfvnlGT9+fJKkd+/eadWqVYYMGZJZs2Y1xLf3338/CxcuzHe/+92Gi+4BvghhDhpBkyZNssMOO+T444/PzTffnBNOOCFJ0qlTp5RKpcyYMaPhuW3bts1RRx2Vk08+Oeuss066deuWXXbZpWEajJqaGl/+ANDI3AUD3wzLL798Ro0alfXWWy+1tbUNn/02bdqkuro6r7/+esNFcxUVFdluu+2y4YYb5pFHHkmvXr1SX19v6nlYhiz+zFZVVWXu3LnZaqutctJJJ+Xpp59uWC+urKwsNTU16dy5c3bYYYdMmTIlBx54YF566aUltuW4HZYNhx12WMaMGZMbbrghzz33XKZMmZINNtggAwYMyLRp07Lrrrvm1ltvzXXXXZezzz47r732WnbZZRefceDfUqp3qw0UrqamJuXl5Zk9e3buueeenHPOOdlll11y8MEHZ6uttsouu+yS5ZdfPj179kz79u3TuXPnz9xObW2taTBgKVZXV9dw8q2+vj6lUmmJx4Cvh09+H//xj3/M3LlzU1dXl0033TQtWrRouLvdwTp8fVRVVWXvvfdOr1690q9fv7z55pvZaaed8rOf/SzHHntsWrZs2fCZHz58eKZOnZoOHTrk9NNPt/8Oy4jF3++1tbXp06dPvve97+Xwww9PixYtctNNN2Xs2LFZb731ctlllzW85rrrrsv777+fpk2b5uc//7k75GAZc+655+bOO+/M2LFj0759+6y44opJkoULF6a8vDxPPPFEbrjhhjz66KNp165dunTpkpNPPjlrrrlmI48cWNbYQ4CC1dXVpby8PHPnzs15552XH//4xzniiCMyatSovPzyyykrK8tTTz2VefPmZfz48SkrK8v666+f1q1bZ8iQIUssIOugHpZeixYtapiadtq0aZk3b166d+/+qVAHLNsWT02XJIcffnj+8pe/ZP78+Vm0aFG+9a1vZc8998zOO+9srQn4mlm0aFG6du2a8847L02bNs0ee+yRESNG5MQTT0xdXV323XffrL766nnzzTfz0ksvZauttspBBx2UxMV1sCxYfDHtggUL8uKLL2b+/Pm5884707Jlyxx00EHZfffdkyRjx47NoEGDctppp2XatGm55557sskmm+TQQw9N4vMOy5Kqqqq89dZb6d27d773ve/lww8/zMMPP5wxY8Zk5syZ6dy5c0aOHJlLL700kydPzoorrpjy8vK0atWqsYcOLIOEOSjQ4p3y6urqHH/88ZkzZ07WXXfdNGvWLEly+eWXp7q6OsOHD88666yThx9+OG+++Wb+93//N4sWLfqnd84BS4f58+fn2muvzcEHH9wQ5Y477rg8+eSTeffdd9O9e/fstdde2W677dKuXTtxDpZhiz+/iz/Do0ePzrPPPpuzzz47K664Yrp06ZKdd945Y8aMyWqrrZYNN9ywkUcMfJlatWqVk08+Ocsvv3xOO+20lJWVpVevXimVSjnllFPyhz/8IfX19WnevHmaNm2a/fbbL8mSMR9YepWXl2fevHnp3bt32rRpkw4dOqRNmza56qqrUl1dnUMPPTR77LFHSqVSLrroovzkJz9J69at06lTp/z85z9v2I7POyw7KisrM2vWrMyYMSOrr756fvOb3+TRRx/Neuutl5/+9Kd58MEHc8YZZ2T8+PHp0aOHY3ngvyLMQYHKysqyaNGiXH311Zk6dWoGDBiQlVZaKUnys5/9LKVSKeedd17uuuuu/PCHP8zWW2+dJNl7770bpsIyDR4svW6//fZccMEFmTFjRoYPH56LLroojzzySA4++OB06NAhv/71r3PFFVfkb3/7W4YMGZIOHTo09pCBf9PiK+hLpVLDBTd1dXWZPHlytthii6yzzjpp1qxZPvzww8yYMSO77757mjVrlhdeeCHf/e53G3v4wJeoTZs2GTJkSOrr63PKKackSXbbbbesv/76+cMf/pCZM2emU6dO2XnnnRumw3OSHpYdF154YSorK3P22Wena9euqampyfXXX58zzzwzSXLIIYdk7733zmabbZaHHnooLVq0aPi8L95fAJZ+i1d5KpVKOfTQQ3PsscfmiCOOSI8ePXLsscdmwIABDc978sknfZ8DXwp7CVCwp59+OjfffHPefffdTJ8+veHxdu3apVevXqmtrc15552X+vr6nHrqqUmSli1bJonF4mEpt+WWW2bWrFm58sors3DhwjRt2jSDBg1K3759kyQ9e/bMueeem9/+9rfp3LlzDjroINPbwTKkvr4+N954Y0qlUvr27dtwQD5//vy8/PLL6dixY5o1a5a33noru+22WzbZZJMccsghOfXUU1NXV5dzzjmnkd8B8GVr27Zthg4dmiQ5+eSTU1tbmz322CN77rnnEs9zEg+WLXV1dXn77bfTrVu3dOvWLcnf76JbfIL+zDPPTEVFRfbZZ5907do1/fr1a3htbW2tKAfLiHHjxuVvf/tbunbtmq233jqbbLJJbr/99kyZMiXf+ta3Gs7HzZ8/P6+88ko6dOjgOx34UthTgK/YP35hb7zxxjnllFNy1lln5aqrrkrXrl2zzTbbJElat26d3r17p6ysLCNHjszKK6/csBZFErfJw1Ksrq4uHTp0yJ577pn6+vpMnDgxc+bMyemnn57k74tFN2vWLEceeWTee++9/PrXv07//v2FOViGVFdX56WXXsozzzyT9u3b5/bbb8+BBx6Y9dZbL5tssklefPHF3H///TnxxBPzox/9KKeddlpatGiR2travPPOO+56h6+ptm3b5ogjjkiTJk0ycuTILFy4MPvuu+8Sn3cn8GDp9o9TzDdp0iRt2rTJ888/n6qqqlRWVqa+vj51dXXp27dv7r333kyYMCGVlZUZOHBgll9++YbX+rzDsmHw4MF58skns8oqq+Tpp5/On/70pwwePDibbbZZ2rZtm7/97W+55ZZbsvrqq+dPf/pTnnrqqUycONExPPClcGYAvkI1NTUN01c+9thjefDBB5MkP/nJT3L00UenQ4cOueqqq/Lwww83vGb55ZfPjjvumPPPP79hLQpg6fbJu1nbt2+ffv36pW/fvlluueXyxz/+MUnSrFmzLFy4MMnfDwCmTZuWp59+utHGDPz7Kisrc9hhh6Vp06Y5+eST8/DDDzccmP/4xz/Oyy+/nMGDB2e99dbLmDFj0qpVq3z44YeZPn161lhjjUYePfBVWjyt5VZbbZX777/fBXWwDKmpqUmpVEp9fX3D/nqSrL/++pk1a1ZuvvnmLFy4MGVlZWnSpElKpVKaNm2aVVZZJePGjcsDDzyQ5P+mwwOWfueee24mT56ciy++ODfffHMOOeSQTJkyJZdcckkmTZqUJHn99ddz//33Z/z48Zk1a1YmTJiQHj16NO7Aga8Nd8zBV2Tx9BVz587NwIED88Ybb2TevHlZa621cs0112SzzTZLTU1NLrroolx00UVJks022yzJ3w/st9tuuyQxNz0sAxaffDvuuOPSoUOHHHLIIQ3T2Vx77bUZPXp0jjjiiDRr1ixJ8t5776VNmzZp3759o40Z+PfV1NSkQ4cOad++fV5++eWsvPLKmTx5ctZaa61su+22+eCDDzJixIiUSqXcd999KSsry913353JkyfnlFNOcbccfM21adMmI0aMsDY0LEMWH2/Pmzcvo0ePzptvvpnvf//76devX/r06ZN77703Y8eOTX19fXbfffdUVlbm7bffzrx583Lsscfm3nvvzWWXXZZtttkmzZs3b+y3A3wB1dXVef7557Pjjjtmgw02yMKFC/PRRx9ltdVWy0cffZQLL7wwLVq0yI477pitt946c+bMScuWLdOiRYvGHjrwNeJsP3xFysrKsmDBguy5555p27ZtzjjjjMydOzennHJKDjjggFx22WXZcsstUyqVctFFF2XcuHFZuHBhw7SWi4lysOxo0qRJLr/88rRo0SIDBgxoiHM333xzPvzwwxxyyCGZNm1a7rrrrjRv3jwdOnRo5BEDX8Tik+uLv5N33nnn7LHHHhk7dmyuvvrq1NbWZrfddstee+2V8vLy/OY3v8lRRx2V9u3bp23btrn22mvTvXv3Rn4XwBfxWevG/OMUd5+nVatWDX8vysHSra6uruFi2l133TXV1dXp2LFjrrjiirzyyis55ZRTcuWVV+bggw/OZZddluuvvz7dunXLK6+8kpYtW2bjjTfOM88844Q9LEPq6ury4Ycf5tVXX224OP6RRx7J9ddfn9NPPz1lZWU54IADMmrUqOy6667p27dvOnbs2MijBr6OnPGHr9CNN96Ytm3bZtSoUVl55ZXzl7/8Jd/73vfy3HPPZcCAAbnmmmvy05/+NKVSKSeffHIeffTRT4U5YOn0yRN3i0/ajxw5Mssvv3xGjx6dJBkwYED23XffJMlll12WO+64I2uvvXZqamoyduzYrLjiio02fuCL+eRn/ZVXXknbtm2z2WabpUWLFlljjTUyePDgXHvttamvr0+fPn3Sp0+fbL311vnggw/StGnTtGzZcokT9cDSa/GdM4sWLcrjjz+e9u3bp3Pnzmnbtu2/vPvtk/Hulltuycorr5yNNtqoqKED/4EmTZqkuro6hx9+eDp37pyRI0emc+fOGTNmTC699NI0adIkJ598csaNG5c77rgjTz75ZD766KNsu+22OfLII5MkkydPTpcuXbJo0aJUVlaaxhaWck2aNEn79u2z8847p0OHDpk1a1aOOeaY7Lvvvg2hrnPnzpkzZ04uv/zybLfddmnbtq3PNvClE+bgK/TGG29k/vz56dKlS5Lk7rvvTrNmzXLyySfnnHPOycEHH5yxY8dmiy22SPv27fPd7363kUcMfJ5PnnRbfKL+gw8+SNu2bRtO5h1zzDGpr69viHP9+/dP//7906RJk4wfPz49evTIkUceaaobWAZ8MsoNHz48jz76aGpra7P55ptn//33zyqrrJILLrgghx9+eK677rqUlZVlyy23tKYcLKMW3zmz77775s0330x5eXm22GKLHHrooVlllVX+aZz75P7Bddddl5EjR+bcc88tevjAf2DatGmZPXt2hgwZks6dO2f69OmZNWtWtthii0yaNClVVVU58cQT06tXr/Tq1Stz587NtGnT8uSTT+bWW2/N448/nokTJ6Zp06aN/VaAz/H6669n7ty5adGiRbp3794Q12+99dZ06NAhhx56aOrq6vLCCy+kTZs26d+/f37yk5+kbdu2jTxy4OtKmIMvyT8eqNfU1GSllVbKnDlzUiqVMnHixEyYMCHXXXdd1ltvvUyaNCm///3vs9VWW2Xs2LHZdNNNk3z29DlA45s/f37OO++89OrVK+uss06S5Pzzz8/48eNz5513pkuXLg1x7thjj01dXV3GjBmTUqmUvn37Zq+99kpFRUW23XZbUQ6WAZ9c4/Wwww7L008/nb333jtTp07NAw88kI8++ihDhgxJt27dcsEFF2To0KG58MILc+GFF2bhwoW57777svzyyzfyuwC+iE+GtbFjx6ZNmzYZPXp0nn766Tz44IM59dRTc9JJJ6Vbt26f2uf/xyh3xhln5LTTTsvPfvazRnkvwL9n7ty5efHFF1NXV5ckueGGG/LHP/4xV1xxRXr16pWhQ4emTZs22XjjjbPTTjvlnXfeyZgxY/KXv/wlXbt2bbjwDlh6HXXUUXn++efzxhtvpFOnTlljjTUyYsSIrLTSSpk/f37eeuutzJ49O8nf73qvra3NpptuKsoBX6lSfX19fWMPApZ1i0/eVVdXZ9q0aWnRokXatWuX6dOn5/3330+3bt2y/fbb5+CDD07fvn2TJMOGDUvz5s3Ttm3bHHbYYdaSg6Xcs88+mz333DObb755Bg8enLXWWiuPPfZYTj/99FRXV+eXv/zlEnGuvr4+BxxwQF555ZXsscce2X///VNZWWm9GViKLViwILfddlv22muvhsduvvnmXHXVVTn33HOz9tprZ+bMmTnggAMya9asrL/++hk2bFhWWWWVTJkyJddee20+/vjjDBw4MGuuuWYjvhPgi1r8vb04uB1zzDFZb731sueeeyZJrr322tx0003p3LlzTjzxxCXi3GdFuVNPPTV9+vRpzLcE/BOfddfr3Llzc+mll2aXXXbJe++9lwMOOCDjxo3LFlts0XBRTllZWbbffvucc845SZKXXnopyy23XFq3bp02bdo0wjsBvqgRI0bkwQcfzDHHHJN27dpl7ty5OeGEE9KxY8dcfvnl+fDDD3PYYYdlypQp6dq1a+bMmZNrr73WvjzwlVMC4L9UX1/fMO3Nfvvtl2nTpmXRokU5+eSTs/3226djx46ZMmVKkjQsGPvWW2/lzTffTO/evRtC3SevzAeWLvX19Vl33XVz9dVX58ADD0xNTU2OPvrobLzxxjn11FMzfPjw9O/fP9dee23D1LWlUinLL798ampqctttt2XvvfdOs2bNGvmdAJ/noosuyo033phZs2bl0EMPTZJMmTIlK664Yrp165b6+vr87ne/yworrJDvfOc7efDBBzN69OgceeSR6dq1a44++uiUSqVUVFQ08jsBvoi6urqG/fgjjzwy8+fPz+TJk7Pllls2PKd///5JkptuuikjR47MiSeemFVWWWWJWS5EOVj6LT7erqqqypQpU/L+++9n7bXXTvPmzTN06NCUlZXlqquuymabbZYtttgitbW1mTlzZrbccssMHjx4iSmqnbCHZcPMmTPzl7/8JQMHDkzPnj1TUVGR1157LVVVVdloo40yd+7cdOvWLWPHjs2DDz6YUqmUbbfdNt26dWvsoQPfACoA/JdKpVJqa2tzxBFHpKKiInvssUcmT56co48+Oh9++GF22223VFZWZv78+bnpppvy3HPP5YknnkhFRUXDlbhJRDlYitXW1qa8vDybbLJJrr766gwcODDnnHNOhg0blh/84AcZMWJETj755PTr1y/jx49Ply5dMm/evJSVlWXcuHFZddVV07p168Z+G8C/0K9fv7z33nu54447Ul1dnaFDh6a6ujoff/xxWrVqlT/96U8577zzcvzxx6dPnz459NBD87vf/S4vvPBCzjrrrKy33nqN/RaAL6Curi719fUpKytLVVVV9tprr1RWVqZNmzapqanJqFGjsuaaa2aVVVZJ8vc4VyqVcvPNN2fYsGEZO3ZsVlpppSTJ+PHjc9ZZZ4lysBT7ZITff//9M2PGjLz77rvp2LFjNt988xx44IFZeeWVUyqVMn369Lz44otp1qxZxo8fn1atWjWEOMtOwLKlrq4ub7/9dpKkoqIib775Zvbaa69sscUW2X///TNy5Misueaa+cUvfpE11lhjiTvhAb5qSgD8hz55h1tZWVlWWmml7Ljjjtlwww1TVVWVs846KyNHjkxdXV369u2bMWPG5IQTTsjUqVPTtWvXjB07NmVlZXbuYSm3OMolyeTJk7PqqqvmjDPOyHHHHZeysrIcccQR2WCDDTJixIiccsop2WuvvfLjH/8406ZNy3PPPZfDDz9clINlQFVVVTp27Jjhw4fn1FNPzX333Zc2bdpk//33zwYbbJCqqqqceOKJ2WGHHRpOvrds2TLf+ta3suaaa1pPDpYBs2bNygorrNAwlV1VVVWefvrpdO/ePcccc0w6deqUu+66K5dddlkOO+ywjB07Nl27dk3y93A/f/78vPrqq+nQoUOS5J577nGnHCwDmjRpkqqqqhxwwAFZbrnlctJJJ+U73/lObr/99lx++eV55ZVXMmHChGy44YZ58MEHs99++6WysjLt27fPNddckyQNMR9Y+lVVVeXjjz/OCiuskNatW2fatGl57bXXstdee2WTTTbJ6aefniZNmuStt97Kcsst1/A6UQ4okjAH/4HFJ+rnzZuXsWPH5t13380TTzzRsMh7ZWVljjrqqJRKpZxxxhkplUrZe++9c88996Suri6tWrVKqVQyfSUs5erq6hoOwI8++ug899xzeeutt7Lddtvl8MMPz4UXXpiampocddRR2WCDDXLOOedk3Lhx+fOf/5wOHTpkwoQJDSf0gKVXXV1dKisrkyS/+93vUl9fn7fffjtjxozJggUL8otf/CIzZ87M/Pnz07t37yTJjBkz8uGHH6ZXr17p37//Egf1wNKnqqoqV1xxRVq2bNkwVe1ZZ52V3/72t2nfvn1atmyZJNlhhx1SV1eXq666KoMHD14izv385z9vuJq+pqYmtbW1ufjii5eY+hJofNOnT0+TJk2y4oorNjz2+uuvZ9q0aTnllFOy6aabpry8PCuvvHIWLFiQ3XffPS+++GJ23nnntGzZsuEOm379+qW8vNxxOyxDzjrrrDzzzDOZPXt2zj333Bx44IEZMWJErrnmmvTq1SunnnpqmjVrlhkzZqRp06YNd8e7Ww4omj0L+DctvlJuwYIF6dOnTz766KO0bds2H374Ye67776sttpqWXHFFdOsWbMceeSRSZJRo0Zl/vz56d+/f8O6M4un0wCWXouvqD/99NPz5z//OUcffXRWWGGFvPvuu9lpp52y7rrrZr/99suYMWMyePDgfPe7382FF16Y2bNnZ7nllnOiHpYRiz/rRx99dJ544onstttuOemkk/LrX/86d9xxR2pra9OnT5+Ul5fnmmuuycKFC3Prrbfmr3/9a4477jifdVhGLFy4MA899FCS5I477sgPfvCD9OjRI5MnT84HH3yQVq1aJUl23HHHJMnVV1+dww8/POedd15WW221JH+/mn7xfvzii/KApcfcuXPTs2fP7LXXXjnggAMa4ty0adPy/vvvp3v37ikvL89tt92WY489NocffnjWXnvtDB8+PIcddli22mqrJbb3ydkzgKXb0KFD85e//CVbbbVVw/ruW2+9dd59991ceeWV6datW9577718/PHHueGGG/LOO+80fOeLckDR7F3Av2HxFTR1dXV54IEH0qlTp4wbNy5t27bN1VdfnUsvvTQrrLBC9thjj7Rr164hzn300UeZNGlS9t9//4ZtLT4JCCzdZsyYkaeffjr77rtvtt122yV+ttFGG+XAAw/MZZddlrKysuy///5Zb7310q5du0YaLfCfevXVVxsC/A477JAk6dmzZ8aNG5f7778/VVVV2WeffXLttdfm8ccfT5s2bXLllVc2XGULLN0qKyszdOjQTJ06NZdddlk6duyYYcOG5W9/+1tGjBiR/v3758Ybb0zHjh2T/D3OlUqlnHXWWbn88sszatSohm3Zj4elV8uWLXPhhRfmkEMOSbNmzbLPPvtkxRVXzHe+8500a9Ys999/f1ZbbbUce+yxGTp0aAYNGpS5c+fmr3/9a1599dVstNFGS2zP9JWwbHjggQfyzDPPZPTo0Vl//fWTJLNnz84jjzyS8vLy9OnTJ+PGjcvEiRPTrFmzNG3aNFdffbV9eaDRCHPwbyiVSqmtrc0+++yTioqKdOrUKd26dUuSDBkyJLW1tbnggguSZIk4d/rpp6e8vDylUsnt8bCMqaury9SpUz/1ua2urs4f//jHvPDCCxkyZEjGjBmTsrKyrLXWWg1T4gHLjtra2nzwwQdp2rRpkr9/xldYYYX84he/yNSpU/PrX/86u+++eyZOnJh58+alffv2ad++fSOPGvh3tG7dOvPmzUvLli1TV1eXu+66K/3798/JJ5+cM844I/369cv48eMb4tzPfvaztG3b9lMn6oGl2+abb57LLrssBxxwQJJk7733Tvv27bP99tvnsssuy4cffphjjz02AwYMSF1dXV5++eWsuOKKDcf2wLJnzpw5adq0adZYY4288soreeihh3LppZemtrY2ixYtSp8+ffLrX/867733Xlq0aJHVVlvNvjzQqIQ5+DeVlZVl0KBB+fnPf54111wz7733Xjp16pQkGTZsWJJk7NixadKkSXbddde0b9++4SR9XV2dK2xhGVNZWZlWrVrl2WefbfgM19fXp6KiImuttVYeeeSRHHLIIZkwYULatm0rysEyqnXr1qmsrMxzzz2XrbbaKhUVFamqqkq7du1yxBFHpHfv3rnlllvSvHnzHHTQQY09XOA/dM455+SDDz7IRRddlAkTJqS+vj4DBgxIkoY4d91116VDhw5Jkh/96EdJ/h7v3TkDy45NN900V155ZUOc+/nPf579998/b731Vt58881UV1dnzpw5+ctf/pLLLrssHTp0yCabbNLIowb+U2ussUbefvvtHHjggXn33Xfz/vvvp0+fPunVq1eqq6szcODA/OxnP8vmm2/e2EMFSJIoBPAf2HzzzXPNNdfkpZdeyoQJE/L+++83/GzYsGE58MADc/755+eRRx5Z4nWiHCx72rZtmyFDhuS+++7LlVdemeT/5p+fP39+evTokY8//jgbbLBBunfv3phDBf4LK620Uvbbb79cccUVufXWW5OkIbRPmzYtq6yySrbddtuGaS6BZVOXLl0a1pPq3r17Jk6cmGuuuSabbbZZTjjhhJSXl2f77bfPBx98sMTrRDlY9iyOc5dddlkuvfTSdOnSJaeccko23XTTXHHFFdlss81yyimnpLy8PNddd13KyspSW1vb2MMG/gPf//73c+6556ampiZbbLFFzjvvvJx66qnZYIMN0qpVq3Tp0iXNmzdv7GECNHDHHPyHNtpoo1x11VXZf//9U15enr59+zZcWTt06NCstNJKDYvIAsu2rbbaKvvtt1/OP//8vPfee9l+++1TKpVy66235qOPPsrqq6/e2EMEvgR77LFHJk+enOOOOy7Tpk1Lz549s2jRotx9993p0qVLBg8enNatWzf2MIEvQefOnXPSSSfltNNOyw033JD6+vpsueWW6dGjR1ZdddUsv/zyjT1E4EvwWXfOjRgxIoMHD85LL72UTp065dvf/naaNGmSmpqalJc7TQbLqh122CE9e/ZMZWVlqqqqkiTvvvtubrnlljRp0iQrrbRSI48Q4P+U6uvr6xt7ELAse/TRR3PAAQfk5z//efr27ZsVV1xxiZ/buYevh/nz5+eWW27J+eefnyRp1apVmjdvnjFjxmTNNdds5NEBX5bZs2fnmmuuydVXX51mzZplueWWS1lZWcaNG5fvfOc7jT084Es2derUjBw5Mk8//XTmzp2bNdZYIzfffHPDnTPulIOvh8XH7YMGDcree+/dsJbkYpadgK+PadOmZffdd0/z5s3TtGnTzJo1K1dccYV9eWCpIsz9g+nTp2f77bfP4MGDG9YagH/lD3/4Qw444ID07ds3hxxySNq2bdvYQwK+Iu+8807eeOONNG/ePN26dbNgNHxNvfbaa3n11VfTokWL9OjR41Mn8ICvj2nTpuWRRx7JzJkzc+CBB6a8vFyUg68hx+3wzbBo0aI88MADeeKJJ9KlS5dsu+226datW2MPC2AJwtwnzJs3LwMHDsxzzz2X4447Tpjj3/Lggw/m8ssvzw033NCw/hQAALBsMeMFfH05bgcAlgbC3P83derUDB48OH/729+SRJjjP1JfX59SqdTwVwAAAGDp4bgdAGhsJtBOcs0112THHXfMSy+9lI022qixh8MyzM49AAAALL0ctwMAjU2YSzJ+/Ph06dIlEyZMyE477dTYw2EZZ+ceAAAAll6O2wGAxmTi/CQjRozIJptskrKysrz55puNPRwAAAAAAAC+hoS5JD/+8Y8bewgAAAAAAAB8zQlz/4HNN9+8sYcAFGDMmDFJkiFDhjTqOICvls86fHP4vMM3g886fHP4vMM3y6RJkxp7CPwTW2yxxVey3Yceeugr2W5js8YcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUob+wBLG169+6d3r17N/YwAAAAAAAA+JpxxxwAAAAAAAAUwB1zAMA33rrrrptJkyY19jCAAjz77LONPQQAAAC+wYQ5AOAb79lnn82QIUMaexjAV2zMmDGNPQQAAAC+4UxlCQAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAA5Y09AACAxrbuuutm0qRJjT0MoADPPvtsYw8BAACAbzBhDgD4xnv22WczZMiQxh4G8BUbM2ZMYw8BAACAbzhTWQIAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAAwhwAAAAAAAAUQJgDAAAAAACAAghzAAAAAAAA/Ec6duzY2ENYpghzAAAAAAAA/EemT5/e2ENYpghzAAAAAAAAUABhDgAAAAAAAAogzAEAAAAAAEABhDkAAAAAAAAogDAHAAAAAAAABRDmAAAAAAAAoADCHAAAAAAAABRAmAMAAAAAAIACCHMAAAAAAABQAGEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFAAYQ4AAAAAAAAKIMwBAAAAAABAAYQ5AAAAAAAAKIAwBwAAAAAAAAUQ5gAAAAAAAKAA5V/0iR988EEuvvjiTJo0Ke+//35WXnnl9O7dOwMGDEh5+f9tZt68eRk3blzuvvvuzJw5M507d84uu+ySAQMGpGnTpktss7q6Otdff31uueWWTJkyJa1bt86WW26ZQw89NO3atfvUGH71q19l4sSJeeONN9KuXbtsvvnm+cUvfpGOHTsu8byqqqqst956qamp+cz3cvfdd6d79+4Nf3766adz0UUX5YUXXkh1dXXWWWedDBo0KP/zP//zRX89AAAAAAAA/5Xf/va3OfLII5d4bMstt8wll1zSSCPi81RXV+fcc8/NbbfdliTZdtttc8IJJ6SysvKfvuYLhbm5c+dm7733zuuvv54tttgiPXv2zNNPP51zzjknf/7znzNu3LiUSqUsWLAg/fr1y/PPP58ePXpkzz33zNtvv53Ro0fn0UcfzRVXXJFmzZo1bPe4447Lb3/726y99trZa6+98s477+T666/PpEmTcssttywR50aMGJHrr78+K6ywQnbZZZdUVVXl9ttvz0MPPZTx48dn1VVXbXjuK6+8kpqammy66aZZd911P/V+2rZt2/D3jzzySA466KC0atUq2223XcrKynLPPfekf//+GT16dLbffvsv8isCAAAAAAD4r7z66qvp2bNnTj755IbH/vGmJ5YeZ599dn7/+9/nkksuSalUypFHHpmLL744Q4cO/aev+UJh7vLLL8/rr7+eE044If369Wt4fNiwYbnzzjvz8MMPZ/PNN8+VV16Z559/Pj179szo0aMbiuDEiRNz6qmn5oorrsjgwYOTJI8++mh++9vfZptttskFF1yQUqmUJLnxxhtz8skn54orrsgxxxyTJHniiSdy/fXXp1u3bpk4cWJWXHHFJEm/fv2y++6756STTsp1113XMK6XX345SbL33ntnyy23/Kfvq66uLieccEJatmyZ2267LZ07d06SDBo0KL169coZZ5yRrbfeeok7AgEAAAAAAL4Kr732Wr797W83dBCWXh999FFuuOGGXHbZZfnBD36QJDn00ENz9913f+7rvtAac1OnTk2nTp2y9957L/H44rvJnnnmmSTJXXfdlVKplJNOOmmJ2/T23nvvrLrqqpkwYULD9JKvvvpq2rdvnwMPPLAhyiXJz372syTJs88+2/DYXXfdlSQ5/PDDl/iP8bvf/W522WWXPPnkk3nhhRcaHl8c5r797W9/7vuaMmVKmjdvnp122qkhyiVJx44ds+GGG2bGjBmZOnXqv/jtAAAAAAAA/PdeffXVrLbaao09jC+strb2K9v2Y4899pVu/7/11FNPpVmzZtlkk00aHuvdu3euvPLKz33dFwpz5513XiZNmvSpO8def/31JEn79u2TJO+88046d+78qTXfSqVSvv3tb2fOnDl57bXXkiQDBgzIH/7wh3zve9/73G0maYhj66yzzqfGtji+PfXUUw2Pvfzyy2nZsmVWXnnlz31f3bp1y+9+97uceOKJSzxeV1eXN998M2VlZWnTps3nbgMAAAAAAOC/VVVVlSlTpuShhx7K1ltvna222irnnntuqqqqGnton6m2tjZHH330V7b90047LUcfffRSG+fefvvtdOnSJXfeeWd22GGHbLHFFjnrrLP+5b+vLxTmPqm+vj6zZs3KxIkTM3bs2HTu3Dm9evVKklRWVv7Tf+DHH3+cJHn33Xc/8+dz587Ngw8+mKFDh6aioiIDBw5s+FlFRUWSfOa2P2u7kydPTqdOnXL++edn6623zve+971sv/32ufbaa1NfX/9P31t1dXUmT56cYcOG5ZVXXslee+2V1q1bf96vAwAAAAAA4L/21ltvpaamJs2bN8+FF16Yo48+Or/97W8zatSoxh7aZ3ryySfz4osvfmXbX7BgQV544YU8+eSTX9k/478xb968vPPOO5kwYUJGjBiRU045Jffee2/OOeecz33dv7142gUXXJBx48Yl+ftdbVdddVVDvFp77bXzxBNP5Jlnnsl6663X8JpZs2blueeeS/J/Ie2THnvssQwYMCBJUlZWltGjR2f99ddv+Pnaa6+dhx56KPfff38GDRrU8Hh9fX0mTZq0xHZnzJiRWbNmZdasWVm4cGF++tOfZsGCBZk0aVLOOOOMvPjiiznzzDM/871ttdVWmTZtWpJkm222yfHHH/+Zz1v8zwS+GXzm4ZvBZx2+OXze4ZvBZx2+OXzega+LHj165PHHH0/btm2TJGuuuWbq6+szbNiwnHDCCZ+a1bCxvfLKK1m4cOESj5VKpQwcODD77rvvv7298ePH55prrlniBqtFixbl1VdfzcYbb/xfj/fLVl5enrlz5+acc87JKquskiQ5+uijc/TRR+e4445LkyaffW/cv/1vsUuXLtlvv/0yZcqU/P73v0/fvn1z5ZVXZq211sp+++2XJ554IkOHDs2IESOywQYb5O23386IESMafpGfdcdaRUVF+vfvn48//jj33Xdfhg0blvnz56d3795Jkj59+uSXv/xlLr744rRs2TLbb799FixYkHHjxmXy5MlLbHfWrFnp0aNHvvWtb+Xcc89tWOvuo48+ysCBA3PrrbemZ8+e2XLLLT81jp/85CdZbrnl8thjj+Xee+/NIYcckgsuuCBNmzb9d39NAAAAAAAA/5bFUW6x7t27p7q6OrNnz06HDh0aaVSfrV+/funXr99Su72vWocOHVJeXt4Q5ZJktdVWy6JFizJ79uwllmz7pFL9583t+C9MmjQpP//5z7P66qvnt7/9bUqlUq666qqMHj06NTU1Dc/bZJNNsv766+eiiy7K2LFjs/XWW//TbU6dOjW77rpr5s6dmwceeCArrbRSkr/fVTdkyJDMmTOn4bldu3bNoYcemmOOOSb77rvvp9aK+0ePP/54+vfvnx122CGjR4/+p8+rqanJMccckzvvvDNHHXVUDjjggC/4GwEAAAAAAPj33XfffTnllFMyadKkhpuO7rjjjpx22ml58sknUyqVGnmEfNKbb76ZbbbZJnfccUe+/e1vJ0nuvvvunHjiiXnyySf/6R2O//Yac5+0+eabZ+ONN84rr7ySt99+O0my//7753e/+11OOumkHHXUURk/fnyuvvrqzJ8/P0mywgorfO42u3Tpkv79+6e6ujqPPPJIw+Mbb7xx7rvvvowaNSpHHHFELrjggtx9991p06bNF9pukqy11lpJknfeeedzn1deXt6wYOHvf//7f7ldAAAAAACA/8aGG26Y+vr6DB8+PG+88UYmTZqUs88+O/vvv78otxRaddVVs+WWW+a4447L888/nz//+c8599xzs/vuu3/utKP/cirLmpqaPPnkk6mvr8+PfvSjT/28c+fOSZIPPvgg3bp1S/L3O9n22WefJZ73/PPPp1QqpXv37kmSv/71r3nrrbfys5/97HO3+UmtW7dumN7yk9tNktVXXz1JMm3atLz11lvp0aNH2rVrt8RzF891unhqyunTp+cvf/lL1lxzzXTt2nWJ53bo0CEVFRWfGgMAAAAAAMCXrW3btrnqqqsyatSo9O7dOy1btsyee+6ZQYMGNfbQ+CfOPvvsjBw5Mv379095eXl23nnnDBs27HNf84XumPv5z3+eI488MrW1tZ/62UsvvZRSqZSVV145Z599djbccMPMnj17iefMnDkzzzzzTNZee+2GO9xGjx6dYcOG5eWXX/7MbSZpiGX33XdfNtpoo9x7772feu59992XysrK/PCHP0yS/OpXv0q/fv1y++23f+q5Tz31VJJk7bXXTpI88cQTOfTQQzNx4sRPPffVV19NdXX1EnODAgAAAAAAfFW++93v5rrrrsszzzyTRx55JIceeqi75ZZiLVu2zKhRo/LUU0/liSeeyHHHHZeKiorPfc2/DHPl5eXp2bNnZs+enauuumqJn11//fV5/vnns/nmm6d9+/bp0aNHPvroo9x4440Nz6mqqspxxx2X6urqHHTQQQ2Pb7fddkmS8847b4ng9/zzz+f6669P+/bts9lmmyX5+3+Ic+bMya9+9at8ckm8iy++OC+//HL22GOPtG7dOkmyzTbbpFQq5eqrr86sWbManvv+++/n/PPPT0VFRXbfffckyWabbZbmzZvnV7/6Vd58882G586fPz+nnXZakmTXXXf9V78iAAAAAAAA+JdK9Z8sXf/E9OnTs/vuu2fatGnZdNNNs8Yaa+TFF1/MY489lpVXXjnXX399OnbsmJqamuy1117561//mp49e6Zr16559NFH8/LLL2e33XbL6aef3lB2a2trc+CBB+YPf/hD1lhjjWy66aaZPn167rvvvpSXl2fcuHHZeOONG8YwatSoXHPNNVl33XWzwQYbZPLkyfnf//3frLXWWrn22mvTqlWrhueed955ufzyy9OuXbtsu+22qaqqyoMPPpjZs2fn5JNPzt57793w3FtvvTXHHXdcmjdvnu233z6VlZV5+OGH884772TPPffMiBEjvszfNwAAAAAAAN9QXyjMJcmMGTNy4YUX5qGHHsoHH3yQDh06pGfPnjn44IPTtm3bhud99NFHueCCCxqet+qqq2avvfbKbrvtliZNlrxBr6qqKldeeWVuv/32TJ06NS1atMhGG22UQw89ND169FjiubW1tbnuuutyyy23ZMqUKenYsWO23XbbHHjggUtEucVuv/32XHfddZk8eXLKy8uz9tpr58ADD8yPf/zjTz33j3/8Yy699NL89a9/TW1tbdZYY4307ds3u+yyyxf6JQIAAAAAAMC/8oXDHAAAAAAAAPCf+5drzAEAAAAAAAD/PWEOAAAAAAAACiDMAQAAAAAAQAGEOQAAAAAAACiAMAcAAAAAAAAFEOYAAAAAAACgAMIcAAAAAAAAFECYAwAAAAAAgAIIcwAAAAAAAFCA/wfs6MQy0Lb10wAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot visualisation of the missing values for each feature of the raw DataFrame, df_tm_market_value_raw\n", "msno.matrix(df_tm_market_value_raw, figsize = (30, 7))" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "date 4070\n", "dtype: int64" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Counts of missing values\n", "tm_bio_null_value_stats = df_tm_market_value_raw.isnull().sum(axis=0)\n", "tm_bio_null_value_stats[tm_bio_null_value_stats != 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The visualisation shows us very quickly that there a few missing values in most of the columns, but the dataset is ready for us." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 4. Data Engineering\n", "Before we answer the questions in the brief through [Exploratory Data Analysis (EDA)](#section5), we'll first need to clean and wrangle the datasets to a form that meet our needs." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.1. Assign Raw DataFrames to New Engineered DataFrames" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "# Assign Raw DataFrames to new Engineered DataFrames\n", "df_tm_market_value = df_tm_market_value_raw.copy()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.2. Dedupe DataFrames\n", "A copy of each player is saved per season, causing duplication if not treated." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value = (df_tm_market_value\n", " .sort_values(['season', 'tm_id', 'date'], ascending=[False, True, False])\n", " #.drop(columns=['league_code', 'season'])\n", " .drop_duplicates(subset=['tm_id', 'date'], keep='first')\n", " )" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No. rows in Historical Player Value DataFrame BEFORE deduplication: 393953\n", "No. rows in DataFrame AFTER deduplication: 140355\n", "\n", "Variance in rows before and after deduplication: 253598\n", "\n", "----------\n" ] } ], "source": [ "print('No. rows in Historical Player Value DataFrame BEFORE deduplication: {}'.format(len(df_tm_market_value_raw)))\n", "print('No. rows in DataFrame AFTER deduplication: {}\\n'.format(len(df_tm_market_value)))\n", "print('Variance in rows before and after deduplication: {}\\n'.format(len(df_tm_market_value_raw) - len(df_tm_market_value)))\n", "print('-'*10)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "9462" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value['tm_id'].nunique()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.3. Clean Date Attribute" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Year" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "scrolled": true }, "outputs": [], "source": [ "df_tm_market_value['year'] = df_tm_market_value['date'].str.split(',').str[-1].str[:5]\n", "df_tm_market_value['year'] = pd.to_numeric(df_tm_market_value['year'], errors='coerce')\n", "df_tm_market_value['year'] = df_tm_market_value['year'].fillna(-1).astype(int).astype(str).replace('-1', np.nan)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Month" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "#\n", "\n", "\n", "##\n", "df_tm_market_value['month'] = df_tm_market_value['date'].str.split(' ').str[0].str.replace(' ', '')\n", "\n", "\n", "##\n", "dict_months = {'Jan': 1,\n", " 'Feb': 2,\n", " 'Mar': 3,\n", " 'Apr': 4,\n", " 'May': 5,\n", " 'Jun': 6,\n", " 'Jul': 7,\n", " 'Aug': 8,\n", " 'Sep': 9,\n", " 'Oct': 10,\n", " 'Nov': 11,\n", " 'Dec': 12\n", " }\n", "\n", "## Map grouped positions to DataFrame\n", "df_tm_market_value['month'] = df_tm_market_value['month'].map(dict_months).fillna(-1).astype(int).astype(str).replace('-1', np.nan)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Day" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value['day'] = df_tm_market_value['date'].str.split(' ').str[1].str[:3].str.replace(',', '')\n", "df_tm_market_value['day'] = pd.to_numeric(df_tm_market_value['day'], errors='coerce')\n", "df_tm_market_value['day'] = df_tm_market_value['day'].fillna(-1).astype(int).astype(str).replace('-1', np.nan)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Date" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value['date'] = pd.to_datetime(df_tm_market_value[['year', 'month', 'day']])" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(140355, 9)" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.4. Keep Only One Row per Year\n", "Take the last value per year as that year's valuation. Ideally, this would be the date closest to September (start of the season), but for now, the current code is fine." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value_grouped = (df_tm_market_value\n", " .loc[df_tm_market_value.groupby(['tm_id', 'year']).date.idxmax(axis=0, skipna=True)]\n", " .reset_index(drop=True)\n", " )" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
market_value_eurclubtm_idleague_codeseasonmarket_value_gbp
02000000Borussia Dortmund26L12004/20051800000.0
16750000Borussia Dortmund26L12005/20066075000.0
27500000Borussia Dortmund26L12006/20076750000.0
38000000Borussia Dortmund26L12007/20087200000.0
45000000Borussia Dortmund26L12008/20094500000.0
.....................
67231200000Dijon FCO894205FR12021/2022180000.0
6723250000Los Angeles FC898751MLS12021/202245000.0
6723325000Atlanta United FC900440MLS12021/202222500.0
67234150000RC Lens905408FR12021/2022135000.0
6723525000FC Cincinnati905609MLS12021/202222500.0
\n", "

67236 rows × 6 columns

\n", "
" ], "text/plain": [ " market_value_eur club tm_id league_code season \\\n", "0 2000000 Borussia Dortmund 26 L1 2004/2005 \n", "1 6750000 Borussia Dortmund 26 L1 2005/2006 \n", "2 7500000 Borussia Dortmund 26 L1 2006/2007 \n", "3 8000000 Borussia Dortmund 26 L1 2007/2008 \n", "4 5000000 Borussia Dortmund 26 L1 2008/2009 \n", "... ... ... ... ... ... \n", "67231 200000 Dijon FCO 894205 FR1 2021/2022 \n", "67232 50000 Los Angeles FC 898751 MLS1 2021/2022 \n", "67233 25000 Atlanta United FC 900440 MLS1 2021/2022 \n", "67234 150000 RC Lens 905408 FR1 2021/2022 \n", "67235 25000 FC Cincinnati 905609 MLS1 2021/2022 \n", "\n", " market_value_gbp \n", "0 1800000.0 \n", "1 6075000.0 \n", "2 6750000.0 \n", "3 7200000.0 \n", "4 4500000.0 \n", "... ... \n", "67231 180000.0 \n", "67232 45000.0 \n", "67233 22500.0 \n", "67234 135000.0 \n", "67235 22500.0 \n", "\n", "[67236 rows x 6 columns]" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value_grouped" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.5. Create `season` attribute" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "#\n", "\n", "## Map season to DataFrame\n", "df_tm_market_value_grouped['season'] = df_tm_market_value_grouped['year'].map(dict_seasons)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " ### 4.6. Drop columns\n", "Drop `date`, `year`, `month`, and `day`" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value_grouped = df_tm_market_value_grouped.drop(['date', 'year', 'month', 'day'], axis=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.7. Rename Columns" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value_grouped = df_tm_market_value_grouped.rename(columns={'market_value': 'market_value_eur'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.8. Convert `market_value` to Pounds" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.90053" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Get EUR to GBP exchange rate\n", "\n", "## Get latest currency rates\n", "c = CurrencyConverter()\n", "\n", "## Get conversion rate from EUR to GBP\n", "rate_eur_gbp = (c.convert(1, 'EUR', 'GBP'))\n", "rate_eur_gbp" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Overwrite\n", "rate_eur_gbp = 0.90\n", "rate_eur_gbp" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value_grouped['market_value_gbp'] = df_tm_market_value_grouped['market_value_eur'] * rate_eur_gbp" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
market_value_eurclubtm_idleague_codeseasonmarket_value_gbp
02000000Borussia Dortmund26L12004/20051800000.0
16750000Borussia Dortmund26L12005/20066075000.0
27500000Borussia Dortmund26L12006/20076750000.0
38000000Borussia Dortmund26L12007/20087200000.0
45000000Borussia Dortmund26L12008/20094500000.0
.....................
67231200000Dijon FCO894205FR12021/2022180000.0
6723250000Los Angeles FC898751MLS12021/202245000.0
6723325000Atlanta United FC900440MLS12021/202222500.0
67234150000RC Lens905408FR12021/2022135000.0
6723525000FC Cincinnati905609MLS12021/202222500.0
\n", "

67236 rows × 6 columns

\n", "
" ], "text/plain": [ " market_value_eur club tm_id league_code season \\\n", "0 2000000 Borussia Dortmund 26 L1 2004/2005 \n", "1 6750000 Borussia Dortmund 26 L1 2005/2006 \n", "2 7500000 Borussia Dortmund 26 L1 2006/2007 \n", "3 8000000 Borussia Dortmund 26 L1 2007/2008 \n", "4 5000000 Borussia Dortmund 26 L1 2008/2009 \n", "... ... ... ... ... ... \n", "67231 200000 Dijon FCO 894205 FR1 2021/2022 \n", "67232 50000 Los Angeles FC 898751 MLS1 2021/2022 \n", "67233 25000 Atlanta United FC 900440 MLS1 2021/2022 \n", "67234 150000 RC Lens 905408 FR1 2021/2022 \n", "67235 25000 FC Cincinnati 905609 MLS1 2021/2022 \n", "\n", " market_value_gbp \n", "0 1800000.0 \n", "1 6075000.0 \n", "2 6750000.0 \n", "3 7200000.0 \n", "4 4500000.0 \n", "... ... \n", "67231 180000.0 \n", "67232 45000.0 \n", "67233 22500.0 \n", "67234 135000.0 \n", "67235 22500.0 \n", "\n", "[67236 rows x 6 columns]" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value_grouped" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.9. Join Bio-Status Dataset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Read in Engineering Bio-Status DataFrame" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "# Import DataFrame as a CSV file\n", "df_tm_bio_status = pd.read_csv(data_dir_tm + f'/engineered/bio-status/tm_player_bio_status_all_1617-2122_latest.csv')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Filter DataFrame for 'Big 5' European Leagues and MLS Players" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "# Filter playerss in the 'Big 5' European Leagues and MLS\n", "df_tm_bio_status_big5_mls = df_tm_bio_status[df_tm_bio_status['league_code'].isin(lst_big5_mls_league_codes)]" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No. rows in DataFrame BEFORE filtration: 9429\n", "No. rows in DataFrame AFTER filtration: 9429\n", "\n", "Variance in rows before and after filtration: 0\n", "\n", "----------\n" ] } ], "source": [ "print('No. rows in DataFrame BEFORE filtration: {}'.format(len(df_tm_bio_status)))\n", "print('No. rows in DataFrame AFTER filtration: {}\\n'.format(len(df_tm_bio_status_big5_mls)))\n", "print('Variance in rows before and after filtration: {}\\n'.format(len(df_tm_bio_status_big5_mls) - len(df_tm_bio_status)))\n", "print('-'*10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Drop `league_code` and `season` columns" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [], "source": [ "df_tm_bio_status = df_tm_bio_status.drop(columns=['league_code', 'season', 'market_value_gbp', 'market_value_eur'])\n", "df_tm_bio_status_big5_mls = df_tm_bio_status_big5_mls.drop(columns=['league_code', 'season', 'market_value_gbp', 'market_value_eur'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Join the Bio Status DataFrame to the Historical Market Value DataFrame" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "# Join the Bio-Status DataFrame to the Market Value DataFrame to form one, unified DataFrame\n", "df_tm_market_value_bio_status = pd.merge(df_tm_market_value_grouped, df_tm_bio_status, left_on='tm_id', right_on='tm_id', how='left')" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No. rows in Market Value DataFrame BEFORE join to Bio-Status data: 67236\n", "No. rows in DataFrame AFTER join: 67236\n", "\n", "Variance in rows before and after join: 0\n", "\n", "----------\n" ] } ], "source": [ "print('No. rows in Market Value DataFrame BEFORE join to Bio-Status data: {}'.format(len(df_tm_market_value_grouped)))\n", "print('No. rows in DataFrame AFTER join: {}\\n'.format(len(df_tm_market_value_bio_status)))\n", "print('Variance in rows before and after join: {}\\n'.format(len(df_tm_market_value_grouped) - len(df_tm_market_value_bio_status)))\n", "print('-'*10)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(67236, 41)" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value_bio_status.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.10. Rename Columns" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [], "source": [ "df_tm_market_value_bio_status = df_tm_market_value_bio_status.rename(columns={'age': 'current_age'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.11. Select Columns of Interest" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tm_idseasonplayer_nameclubcurrent_clubleague_codecurrent_agemarket_value_gbpmarket_value_eurdobpobbirth_yearpositionposition_codeposition_groupedoutfielder_goalkeeperheightfootcitizenshipsecond_citizenshipplayer_agent
0262004/2005roman weidenfellerBorussia DortmundretiredL141.01800000.020000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
1262005/2006roman weidenfellerBorussia DortmundretiredL141.06075000.067500001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
2262006/2007roman weidenfellerBorussia DortmundretiredL141.06750000.075000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
3262007/2008roman weidenfellerBorussia DortmundretiredL141.07200000.080000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
4262008/2009roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
5262010/2011roman weidenfellerBorussia DortmundretiredL141.04050000.045000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
6262011/2012roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
7262012/2013roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
8262013/2014roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
9262014/2015roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
\n", "
" ], "text/plain": [ " tm_id season player_name club current_club \\\n", "0 26 2004/2005 roman weidenfeller Borussia Dortmund retired \n", "1 26 2005/2006 roman weidenfeller Borussia Dortmund retired \n", "2 26 2006/2007 roman weidenfeller Borussia Dortmund retired \n", "3 26 2007/2008 roman weidenfeller Borussia Dortmund retired \n", "4 26 2008/2009 roman weidenfeller Borussia Dortmund retired \n", "5 26 2010/2011 roman weidenfeller Borussia Dortmund retired \n", "6 26 2011/2012 roman weidenfeller Borussia Dortmund retired \n", "7 26 2012/2013 roman weidenfeller Borussia Dortmund retired \n", "8 26 2013/2014 roman weidenfeller Borussia Dortmund retired \n", "9 26 2014/2015 roman weidenfeller Borussia Dortmund retired \n", "\n", " league_code current_age market_value_gbp market_value_eur dob \\\n", "0 L1 41.0 1800000.0 2000000 1980-08-06 \n", "1 L1 41.0 6075000.0 6750000 1980-08-06 \n", "2 L1 41.0 6750000.0 7500000 1980-08-06 \n", "3 L1 41.0 7200000.0 8000000 1980-08-06 \n", "4 L1 41.0 4500000.0 5000000 1980-08-06 \n", "5 L1 41.0 4050000.0 4500000 1980-08-06 \n", "6 L1 41.0 4500000.0 5000000 1980-08-06 \n", "7 L1 41.0 4500000.0 5000000 1980-08-06 \n", "8 L1 41.0 4500000.0 5000000 1980-08-06 \n", "9 L1 41.0 4500000.0 5000000 1980-08-06 \n", "\n", " pob birth_year position position_code position_grouped \\\n", "0 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "1 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "2 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "3 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "4 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "5 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "6 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "7 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "8 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "9 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "\n", " outfielder_goalkeeper height foot citizenship second_citizenship \\\n", "0 Goalkeeper 188.0 left Germany NaN \n", "1 Goalkeeper 188.0 left Germany NaN \n", "2 Goalkeeper 188.0 left Germany NaN \n", "3 Goalkeeper 188.0 left Germany NaN \n", "4 Goalkeeper 188.0 left Germany NaN \n", "5 Goalkeeper 188.0 left Germany NaN \n", "6 Goalkeeper 188.0 left Germany NaN \n", "7 Goalkeeper 188.0 left Germany NaN \n", "8 Goalkeeper 188.0 left Germany NaN \n", "9 Goalkeeper 188.0 left Germany NaN \n", "\n", " player_agent \n", "0 Jörg Neubauer \n", "1 Jörg Neubauer \n", "2 Jörg Neubauer \n", "3 Jörg Neubauer \n", "4 Jörg Neubauer \n", "5 Jörg Neubauer \n", "6 Jörg Neubauer \n", "7 Jörg Neubauer \n", "8 Jörg Neubauer \n", "9 Jörg Neubauer " ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "## Define columns\n", "cols = ['tm_id',\n", " 'season',\n", " 'player_name',\n", " 'club',\n", " 'current_club',\n", " 'league_code',\n", " 'current_age',\n", " 'market_value_gbp',\n", " 'market_value_eur',\n", " 'dob',\n", " 'pob',\n", " 'birth_year',\n", " 'position',\n", " 'position_code',\n", " 'position_grouped',\n", " 'outfielder_goalkeeper',\n", " 'height',\n", " 'foot',\n", " 'citizenship',\n", " 'second_citizenship',\n", " 'player_agent'\n", " ]\n", "\n", "## Select columns of interest\n", "df_tm_market_value_bio_status_select = df_tm_market_value_bio_status[cols]\n", "\n", "## Sort by 'tm_id' and 'season' ascending\n", "df_tm_market_value_bio_status_select = df_tm_market_value_bio_status_select.sort_values(['tm_id', 'season'], ascending=[True, True])\n", "\n", "## Drop index\n", "df_tm_market_value_bio_status_select = df_tm_market_value_bio_status_select.reset_index(drop=True)\n", "\n", "## Drop duplicates\n", "df_tm_market_value_bio_status_select = df_tm_market_value_bio_status_select.drop_duplicates()\n", "\n", "## Display DataFrame\n", "df_tm_market_value_bio_status_select.head(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.12. Determine Retired Players" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [], "source": [ "# determine current season from today's date\n", "# if season does not appear in the dataset, they've retired - is retired attribute" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [], "source": [ "# add other attributes\n", "# current age / age of season - see TM Bio Status ntb for how to calculate some of these\n", "# current club / club of season\n", "# add 'current' to the following: contract_expires, contract_option, on_loan_from, on_loan_from_country, loan_contract_expiry" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [], "source": [ "## DOUBLE CHECK ATTRIBUTES SELECTED IN FINAL DATASET" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.13. Filter Players in 'Big 5' European Leagues\n", "Export the engineered DataFrame as a CSV file." ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [], "source": [ "# Filter playerss in the 'Big 5' European Leagues and MLS\n", "df_tm_market_value_bio_status_select_big5_mls = df_tm_market_value_bio_status_select[df_tm_market_value_bio_status_select['league_code'].isin(lst_big5_mls_league_codes)]" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No. rows in DataFrame BEFORE filtration: 67236\n", "No. rows in DataFrame AFTER filtration: 67236\n", "\n", "Variance in rows before and after filtration: 0\n", "\n", "----------\n" ] } ], "source": [ "print('No. rows in DataFrame BEFORE filtration: {}'.format(len(df_tm_market_value_bio_status_select)))\n", "print('No. rows in DataFrame AFTER filtration: {}\\n'.format(len(df_tm_market_value_bio_status_select_big5_mls)))\n", "print('Variance in rows before and after filtration: {}\\n'.format(len(df_tm_market_value_bio_status_select) - len(df_tm_market_value_bio_status_select_big5_mls)))\n", "print('-'*10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.14. Exporting the Engineered DataFrames\n", "Export the engineered DataFrame as a CSV file." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### All players" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "## Filename\n", "file_name = 'tm_player_valuations_all'\n", "\n", "## Full season string\n", "full_season_string = '2016/2017-2021/2022'\n", "\n", "## Short season string\n", "short_season_string = '1617-2122'" ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [], "source": [ "# Export DataFrame as a CSV file\n", "\n", "## Export a copy to the 'archive' subfolder of the TM folder, including the date\n", "df_tm_market_value_bio_status_select.to_csv(data_dir_tm + f'/engineered/historical_market_values/archive/{file_name}_{short_season_string}_last_updated_{today}.csv', index=None, header=True)\n", "\n", "## Export another copy to the TM folder called 'latest' (can be overwritten)\n", "df_tm_market_value_bio_status_select.to_csv(data_dir_tm + f'/engineered/historical_market_values/{file_name}_{short_season_string}_latest.csv', index=None, header=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### 'Big 5' European and MLS Players" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [], "source": [ "## Filename\n", "file_name = 'tm_player_valuations_big5_mls'\n", "\n", "## Full season string\n", "full_season_string = '2016/2017-2021/2022'\n", "\n", "## Short season string\n", "short_season_string = '1617-2122'" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [], "source": [ "## 'Big 5' European Leagues and MLS\n", "\n", "### Export a copy to the 'archive' subfolder of the TM folder, including the date\n", "df_tm_market_value_bio_status_select_big5_mls.to_csv(data_dir_tm + f'/engineered/historical_market_values/archive/tm_bio_status_big5_mls_{short_season_string}_last_updated_{today}.csv', index=None, header=True)\n", "\n", "### Export another copy to the TM folder called 'latest' (can be overwritten)\n", "df_tm_market_value_bio_status_select_big5_mls.to_csv(data_dir_tm + f'/engineered/historical_market_values/tm_bio_status_big5_mls_{short_season_string}_latest.csv', index=None, header=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 5. Exploratory Data Analysis" ] }, { "cell_type": "code", "execution_count": 87, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
tm_idseasonplayer_nameclubcurrent_clubleague_codecurrent_agemarket_value_gbpmarket_value_eurdobpobbirth_yearpositionposition_codeposition_groupedoutfielder_goalkeeperheightfootcitizenshipsecond_citizenshipplayer_agent
0262004/2005roman weidenfellerBorussia DortmundretiredL141.01800000.020000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
1262005/2006roman weidenfellerBorussia DortmundretiredL141.06075000.067500001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
2262006/2007roman weidenfellerBorussia DortmundretiredL141.06750000.075000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
3262007/2008roman weidenfellerBorussia DortmundretiredL141.07200000.080000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
4262008/2009roman weidenfellerBorussia DortmundretiredL141.04500000.050000001980-08-06Diez1980.0GoalkeeperGKGoalkeeperGoalkeeper188.0leftGermanyNaNJörg Neubauer
\n", "
" ], "text/plain": [ " tm_id season player_name club current_club \\\n", "0 26 2004/2005 roman weidenfeller Borussia Dortmund retired \n", "1 26 2005/2006 roman weidenfeller Borussia Dortmund retired \n", "2 26 2006/2007 roman weidenfeller Borussia Dortmund retired \n", "3 26 2007/2008 roman weidenfeller Borussia Dortmund retired \n", "4 26 2008/2009 roman weidenfeller Borussia Dortmund retired \n", "\n", " league_code current_age market_value_gbp market_value_eur dob \\\n", "0 L1 41.0 1800000.0 2000000 1980-08-06 \n", "1 L1 41.0 6075000.0 6750000 1980-08-06 \n", "2 L1 41.0 6750000.0 7500000 1980-08-06 \n", "3 L1 41.0 7200000.0 8000000 1980-08-06 \n", "4 L1 41.0 4500000.0 5000000 1980-08-06 \n", "\n", " pob birth_year position position_code position_grouped \\\n", "0 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "1 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "2 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "3 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "4 Diez 1980.0 Goalkeeper GK Goalkeeper \n", "\n", " outfielder_goalkeeper height foot citizenship second_citizenship \\\n", "0 Goalkeeper 188.0 left Germany NaN \n", "1 Goalkeeper 188.0 left Germany NaN \n", "2 Goalkeeper 188.0 left Germany NaN \n", "3 Goalkeeper 188.0 left Germany NaN \n", "4 Goalkeeper 188.0 left Germany NaN \n", "\n", " player_agent \n", "0 Jörg Neubauer \n", "1 Jörg Neubauer \n", "2 Jörg Neubauer \n", "3 Jörg Neubauer \n", "4 Jörg Neubauer " ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df_tm_market_value_bio_status_select.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 6. Summary\n", "This Jupyter notebook engineered scraped football data from [TransferMarkt](https://www.transfermarkt.co.uk/) using [pandas](http://pandas.pydata.org/) for data manipulation through DataFrames." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 7. Next Steps\n", "The step is to use this data and match it to FBref, 21st Club, Opta, FIFA, and other datasets." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "___\n", "\n", "\n", "\n", "## 8. References\n", "\n", "#### Data and Web Scraping\n", "* [tyrone_mings GitHub repository](https://github.com/FCrSTATS/tyrone_mings) by [FCrSTATS](https://github.com/FCrSTATS)\n", "* [Python Package Index (PyPI) tyrone-mings library](https://pypi.org/project/tyrone-mings/)\n", "* [Beyond crowd judgments: Data-driven estimation of market value in association football](https://www.sciencedirect.com/science/article/pii/S0377221717304332) by Oliver Müllera, Alexander Simons, and Markus Weinmann.\n", "* [06/04/2020: BBC - Premier League squads 'drop £1.6bn in value'](https://www.bbc.co.uk/sport/football/52221463)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "***Visit my website [EddWebster.com](https://www.eddwebster.com) or my [GitHub Repository](https://github.com/eddwebster) for more projects. If you'd like to get in contact, my Twitter handle is [@eddwebster](http://www.twitter.com/eddwebster) and my email is: edd.j.webster@gmail.com.***" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[Back to the top](#top)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "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.7.6" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "oldHeight": 642, "position": { "height": "664px", "left": "1119px", "right": "20px", "top": "-7px", "width": "489px" }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "varInspector_section_display": "block", "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }