# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     name: python3
# ---

# + [markdown] id="view-in-github" colab_type="text"
# <a href="https://colab.research.google.com/github/tedteske/bounded_lognorm/blob/master/Applications_100m_Sprints.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>

# + id="h4uhGmkQZpZL"
# !cp "drive/My Drive/Colab Notebooks/bounded lognorm/bounded_lognorm.py" .
from bounded_lognorm import bounded_lognorm

from warnings import simplefilter
simplefilter(action='ignore', category=FutureWarning)

from scipy.stats import norm, truncnorm, lognorm, skew, kurtosis, normaltest
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set(style='darkgrid')
plt.rcParams["font.family"] = "serif"
plt.rcParams["figure.figsize"] = [10, 10/1.6]

# + [markdown] id="uQckoVP9aMqF"
# What are the fastest possible 100m sprint times?
#
# Let's first load data from the 2004-2016 Olympics. See [here](https://deepblue.lib.umich.edu/data/concern/data_sets/cr56n184r?locale=en) for details on this dataset.

# + colab={"base_uri": "https://localhost:8080/", "height": 197} id="p8WKhJqEaKyI" outputId="6092c965-2625-4467-9790-20cc8618cabc"
url = 'https://deepblue.lib.umich.edu/data/downloads/qn59q4716?locale=en'
sprint_data = pd.read_csv(url, encoding="ISO-8859-1")
sprint_data.head()

# + [markdown] id="zc0kRcevaWlH"
# Isolate the 100m sprint times, clean up the `MARK` field (time in seconds), and convert to average speed (meters per second). 

# + colab={"base_uri": "https://localhost:8080/", "height": 197} id="rXCIS24uaTOv" outputId="fe50ef4f-1b20-45ef-ce31-f79d473c3dab"
sprint_data = sprint_data[sprint_data.Race == "100 m"]
sprint_data['speed'] = sprint_data.MARK.str.split(expand=True)[0]
sprint_data['speed'] = pd.to_numeric(sprint_data['speed'],'coerce')
sprint_data = sprint_data[sprint_data['speed']>0]
sprint_data['speed'] = 100 / sprint_data['speed']
sprint_data.head()

# + colab={"base_uri": "https://localhost:8080/", "height": 406} id="ngt-OQseaZGu" outputId="6f926bda-8223-4a85-9556-d331d4a4c201"
speeds_M = sprint_data[sprint_data.Gender == 'M']['speed']
shapes, results = bounded_lognorm.fit(speeds_M, MLE=False, verbose=True,
                                      flower=0)
shapes_rounded = shapes.round(2)
label = (    'mode=' + str(shapes_rounded[0]) +
          ', sigma=' + str(shapes_rounded[1]) +
          ', lower=' + str(shapes_rounded[2]) +
          ', upper=' + str(shapes_rounded[3]))
xdata = np.linspace(7, 11, len(speeds_M))
sns.lineplot(xdata, bounded_lognorm.pdf(xdata, *shapes), label=label)
sns.distplot(speeds_M[speeds_M>7], kde=False, norm_hist=True)
plt.xlabel("Men's 100m Sprints, Average Speeds (m/sec), 2004-2016 Olympics")
plt.legend()
plt.show()

# + [markdown] id="QcxHAZShaj4J"
# Convert the estimated upper bound from average speed (m/sec) to time (sec/100m).

# + colab={"base_uri": "https://localhost:8080/"} id="GG6hFs9lafYv" outputId="5e373431-6177-4d5f-85fd-49027f1d9e8c"
bpt = 100/shapes[-1] 
bpt.round(2)

# + [markdown] id="c_vigAnKap2X"
# With a 95% confidence interval of

# + colab={"base_uri": "https://localhost:8080/"} id="dPLtYdqjamC3" outputId="c48cb616-940a-4115-b891-abd3d6fb4999"
stdev = np.sqrt(np.diag(results[1]))[-1]
conf_interval = np.array([shapes[-1] + 2 * stdev, 
                          shapes[-1] - 2 * stdev])
(100/conf_interval).round(2)

# + [markdown] id="74cR2O61awXs"
# For comparison, Usain Bolt holds the current record of 9.58 seconds, set at the World Championships in 2009, so outside this sample. The estimates are consistent with anecdotes that Bolt sometimes showboats before the finish line and could have done better had he given 100%. Also you can find another estimate of 9.44 at [this article](https://www.bbc.com/future/article/20120712-will-we-ever-run-100m-in-9-secs).

# + colab={"base_uri": "https://localhost:8080/", "height": 406} id="yZA5gdm7a07o" outputId="81f3a552-a283-464a-9fdc-68bf2d7cdb4e"
speeds_W = sprint_data[sprint_data.Gender == 'F']['speed']
shapes, results = bounded_lognorm.fit(speeds_W, 
                                      MLE=False, verbose=True,
                                      fmode=speeds_W.mode()[0],
                                      flower=0)
shapes_rounded = shapes.round(2)
label = (    'mode=' + str(shapes_rounded[0]) +
          ', sigma=' + str(shapes_rounded[1]) +
          ', lower=' + str(shapes_rounded[2]) +
          ', upper=' + str(shapes_rounded[3]))
xdata = np.linspace(7, 10, len(speeds_W))
sns.lineplot(xdata, bounded_lognorm.pdf(xdata, *shapes), label=label)
sns.distplot(speeds_W[speeds_W>7], kde=False, norm_hist=True)
plt.xlabel("Women's 100m Sprints, Average Speeds (m/sec), 2004-2016 Olympics")
plt.legend()
plt.show()

# + [markdown] id="nYW6FFOKa9EP"
# Convert the estimated upper bound from average speed (m/sec) to time (sec/100m).

# + colab={"base_uri": "https://localhost:8080/"} id="ihNU3QLHa6Tf" outputId="04d529fa-02cd-44f2-80c4-2af3cf278304"
bpt = 100/shapes[-1] 
bpt.round(2)

# + colab={"base_uri": "https://localhost:8080/"} id="aU-BKhTMa_oW" outputId="ad56fa08-5ea5-43fa-c4c5-1f1712b22f11"
stdev = np.sqrt(np.diag(results[1]))[-1]
conf_interval = np.array([shapes[-1] + 2 * stdev, 
                          shapes[-1] - 2 * stdev])
(100/conf_interval).round(2)

# + [markdown] id="zLKKIevZbCnp"
# For comparison, <NAME> holds the current record of 10.49 seconds, set in 1988(!), so outside this sample. 

# + [markdown] id="i0BnJl5_bIuQ"
# But aren't we assuming that the upper bound, which is outside the range of the sample data, is nonetheless inherent in the data?
#
# Here is an example of a random sample of 10,000 fictional runners, each having 10 qualities with values ranging from 0 to 1. The sum of the runners' qualities therefore can range from 0 to 10. The perfect runner is a 10 and the perfectly worst runner is a 0

# + colab={"base_uri": "https://localhost:8080/", "height": 407} id="EmtoEEu6bB6E" outputId="3daf23e8-f977-4e7a-b757-e4a233bebc12"
runners = np.random.random_sample(size=(10, 10000))
runner_sums = runners.sum(axis=0)
sns.distplot(runner_sums, kde=False)

# + [markdown] id="zLJEo-UkbnAZ"
# Say we don't know the value sum of the perfect runner, but we do of the worst (0). Let's estimate the perfect runner.

# + colab={"base_uri": "https://localhost:8080/"} id="nprGESFUbkAq" outputId="6f06f1ef-7877-4b2c-e986-1a2dc6f7e1ae"
shapes, results = bounded_lognorm.fit(runner_sums, 
                                      MLE=False, verbose=True,
                                      flower=0)
upper_estd = shapes[-1]
print("The best possible runner, estimated:", upper_estd.round(2))

# + colab={"base_uri": "https://localhost:8080/"} id="a9i9n17Mbyng" outputId="fd2aec5c-b64a-4454-bb59-f1b0abcbd743"
stdev = np.sqrt(np.diag(results[1]))[-1]
conf_interval = np.array([upper_estd - 2 * stdev, upper_estd + 2 * stdev])
print("with a ~95% confidence interval of", conf_interval.round(2))

# + [markdown] id="LSbrSZlnb6hX"
# These are much closer to the theoretically perfect runner (with value sum = 10) than the best from the sample.

# + colab={"base_uri": "https://localhost:8080/"} id="S1hB_Q_pb04I" outputId="c8040fcf-55a9-4c3f-b9a0-99c606f8ee7e"
print("The best runner in the sample:", max(runner_sums).round(2))

StarcoderdataJupyterScriptsDedupFiltered