<jupyter_start><jupyter_text>We use the [Kaggle Olympic Athletes data set](https://www.kaggle.com/heesoo37/120-years-of-olympic-history-athletes-and-results) to investigate changes of athletes' physique over time.First, we load the data set and drop the columns we don't need.<jupyter_code>df_athletes = pd.read_csv('./data/athlete_events.csv')
df_athletes.drop(columns=['Season','Games','Age','City'], inplace=True)<jupyter_output><empty_output><jupyter_text>Next, we add a column for the *body mass index (BMI)* which will serve as a proxy to investigate athletes' strength.We'll drop all rows that have missing values for both *Height* and *Weight*. If one value is missing, we have an NaN in the BMI row. However, we don't perform any modeling in this notebook, so the NaNs don't cause trouble when calculating first and second order statistics.<jupyter_code>df_athletes.insert(5,"BMI",df_athletes.Weight/(df_athletes.Height/100)**2)
df_athletes.dropna(axis=0, how='all', subset=['Height','Weight'], inplace = True)
df_athletes.head(15)<jupyter_output><empty_output><jupyter_text>A quick look at the numeric values of the data set reveals that there are only few values missing.<jupyter_code>df_athletes.describe()<jupyter_output><empty_output><jupyter_text>Next, we take a look at how much data we have for individual sports. We are interested in team sports where body size potentially matters a lot, such as basketball. We see that we have a good amount of data for ice hockey, football, hockey, basketball, water polo, handball, and volleyball.<jupyter_code>df_athletes_counts = df_athletes.groupby(['Sport','Event']).count().sort_values(by='ID', ascending=False)
df_athletes_counts.head(25)<jupyter_output><empty_output><jupyter_text>Let's take a quick look at the number of *Height* and *Weight* measurements we have for our three sports. From 1960 on, we have at least 100 samples for each sport, which seems reasonable. Thus, we decide to look at all years starting at 1960.<jupyter_code>sports_list = ['Basketball','Ice Hockey','Handball']
for sport in sports_list:
    plt.plot(df_athletes[(df_athletes.Sport == sport)].groupby(['Year']).count()['BMI'])
plt.title('Values for Weight & Height')
plt.legend(sports_list)
plt.show()<jupyter_output><empty_output><jupyter_text>Part I: Changes in Body Size We first consider the evolution of *height* over time. A good way of displaying distributions are violin plots. As an example, we plot the height distributions for basketball for all olympic games<jupyter_code># data frame with all basketball players
df_athletes_basketball = df_athletes[(df_athletes.Sex == 'M')&(df_athletes.Sport == 'Basketball')&(df_athletes.Year >= 1960)]
# violin plot
fig, ax = plt.subplots(figsize=(10,5))
sns.violinplot(x='Year', y='Height', data = df_athletes_basketball, ax=ax)
ax.set_title('Height Distribution in Olympic Basketball Teams')
#sns.set(font_scale=1)
plt.show()<jupyter_output><empty_output><jupyter_text>A quick comparison reveals that mean and median do not differ much. Still, we choose to work with the median to limit the effect of outliers.<jupyter_code>display(df_athletes[(df_athletes.Sex == 'M')&(df_athletes.Sport == 'Basketball')].groupby('Year').mean())
display(df_athletes[(df_athletes.Sex == 'M')&(df_athletes.Sport == 'Basketball')].groupby('Year').median())<jupyter_output><empty_output><jupyter_text>Below, we define a function that plots the median height for each year.<jupyter_code>def plot_stuff(sport_list=['Basketball'],sex='M',metric='Height', min_year = 0, plot_medal = True):
    """ Plots the median metric for each year for different sports
    
        Args:
            sports_list (str or list): list of sports to be plotted
            sex (str)
            metric (str): Height, Weight, or BMI
            min_year (int)
            plot_medal (bool): whether or not to include gold medalists
    """
    plt.subplots(figsize=(10,6))
    if type(sport_list) != list:
        sport_list = [sport_list]
    legend_list = []
    for sport in sport_list:
        id_bool = (df_athletes['Sex'] == sex) & (df_athletes['Sport'] == sport)\
                & (df_athletes['Year'] > min_year) 
        df_tot = df_athletes.loc[id_bool]
        plt.plot(df_tot.groupby('Year').median()[metric])
        legend_list.append('{}'.format(sport))
    if plot_medal:
        plt.gca().set_prop_cycle(None)        
        for sport in sport_list:            
            id_bool_gold = (df_athletes['Sex'] == sex) & (df_athletes['Sport'] == sport)\
                    & (df_athletes['Year'] > min_year) & (df_athletes['Medal'] == 'Gold')
            df_gold = df_athletes.loc[id_bool_gold]
            plt.plot(df_gold.groupby('Year').mean()[metric],'--',alpha=0.6)        
    if plot_medal:    
        plt.title(metric+', Gold medalists dashed')
    else:
        plt.title('Median Athlete ' + metric)
    plt.legend(legend_list)
    plt.rc('legend', fontsize=12)
    plt.rc('axes', labelsize=12)    
    plt.show()<jupyter_output><empty_output><jupyter_text>We plot the median athletes' height.<jupyter_code>plot_stuff(sport_list=['Basketball', 'Volleyball','Handball','Ice Hockey'], metric='Height', min_year = 1960, plot_medal = False)<jupyter_output><empty_output><jupyter_text>Part II: Do you even lift? We plot the median athletes' BMI.<jupyter_code>plot_stuff(sport_list=['Basketball', 'Volleyball','Handball','Ice Hockey'], metric='BMI', min_year = 1960, plot_medal = False)<jupyter_output><empty_output><jupyter_text>Part III: Champions vs. Average Next, we'll look at what can be said about the gold medalists versus the average in every year. We can plot the median BMI in this case (gold medalists dashed).<jupyter_code>plot_stuff(sport_list=['Basketball','Ice Hockey','Handball','Volleyball'], metric='BMI', min_year = 1950)<jupyter_output><empty_output><jupyter_text>However, this plot seems a bit messy. A different way to gain insight is by showing the difference between gold medal and average. To have more information in one picture, we'll do this in a scatter plot.<jupyter_code>def scatter_medal(sport_list=['Basketball'],sex='M',metric='Height', min_year = 0):
    """ Plots the median metric for each year for different sports
    
        Args:
            sports_list (str or list): list of sports to be plotted
            sex (str)
            metric (str): Height, Weight, or BMI
            min_year (int)
            plot_medal (bool): whether or not to include gold medalists
    """
    plt.subplots(figsize=(10,6))
    if type(sport_list) != list:
        sport_list = [sport_list]
    legend_list = []
    for sport in sport_list:
        # data frame for all athletes
        id_bool = (df_athletes['Sex'] == sex) & (df_athletes['Sport'] == sport)\
                & (df_athletes['Year'] > min_year) 
        df_tot = df_athletes.loc[id_bool]
        # data frame for gold medalists
        id_bool_gold = (df_athletes['Sex'] == sex) & (df_athletes['Sport'] == sport)\
                    & (df_athletes['Year'] > min_year) & (df_athletes['Medal'] == 'Gold')
        df_gold = df_athletes.loc[id_bool_gold]        
#        plt.plot(df_tot.groupby('Year').median()[metric])
        plt.scatter(df_gold.groupby('Year').median()['Height'] - df_tot.groupby('Year').median()['Height']\
                  , df_gold.groupby('Year').median()['Weight'] - df_tot.groupby('Year').median()['Weight'])        
        legend_list.append('{}'.format(sport))
     
        #color = next(ax._get_lines.prop_cycler)['color']
        #legend_list.append('{}: winners'.format(sport))
        plt.ylim(-12, 12)
        plt.xlim(-12, 12)
    
    plt.title('Gold Medalists minus Average')
    plt.legend(legend_list)
    plt.xlabel('Height Difference')
    plt.ylabel('Weight Difference')
    plt.rc('legend', fontsize=12)
    plt.rc('axes', labelsize=12)    
    plt.show()
scatter_medal(['Basketball', 'Volleyball','Handball','Ice Hockey'], min_year = 1960)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13045112781954887, 'fraction_numerical': 0.009523809523809525, 'mean_word_length': 4.264511873350924, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 54, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '191059', 'license': 'FTL', 'n_tokens_mistral': 2709, 'n_tokens_neox': 2492, 'n_words': 664, 'path': 'olympics.ipynb', 'repo_name': 'larpal/olympics_body_composition_EDA', 'size': '7980'}