美文网首页
探索性数据分析-RedCard-EDA

探索性数据分析-RedCard-EDA

作者: ForgetThatNight | 来源:发表于2018-07-03 22:54 被阅读67次

    1-Redcard-Dataset

    探索性数据分析(EDA)

    有趣的数据集,包含球员和裁判之间的故事!

    数据集介绍点击: here.

    任务:

    探索性数据分析(EDA). 挑战目标: 这些裁判在给红牌的时候咋想的呢,会不会被跟球员的肤色有关?

    %matplotlib inline
    %config InlineBackend.figure_format='retina'
    
    from __future__ import absolute_import, division, print_function
    import matplotlib as mpl
    from matplotlib import pyplot as plt
    from matplotlib.pyplot import GridSpec
    import seaborn as sns
    import numpy as np
    import pandas as pd
    import os, sys
    from tqdm import tqdm
    import warnings
    warnings.filterwarnings('ignore')
    sns.set_context("poster", font_scale=1.3)
    
    import missingno as msno
    import pandas_profiling
    
    from sklearn.datasets import make_blobs
    import time
    

    数据简介:

    数据包含球员和裁判的信息,2012-2013年的比赛数据,总共设计球员2053名,裁判3147名,特征列表如下:

    -- https://docs.google.com/document/d/1uCF5wmbcL90qvrk_J27fWAvDcDNrO9o_APkicwRkOKc/edit

    # Uncomment one of the following lines and run the cell:
    
    df = pd.read_csv("redcard.csv.gz", compression='gzip')
    
    df.shape
    

    输出 (146028, 28)

    df.head()
    
    df.describe().T
    
    df.dtypes
    
    all_columns = df.columns.tolist()
    all_columns
    

    输出:
    ['playerShort',
    'player',
    'club',
    'leagueCountry',
    'birthday',
    'height',
    'weight',
    'position',
    'games',
    'victories',
    'ties',
    'defeats',
    'goals',
    'yellowCards',
    'yellowReds',
    'redCards',
    'photoID',
    'rater1',
    'rater2',
    'refNum',
    'refCountry',
    'Alpha_3',
    'meanIAT',
    'nIAT',
    'seIAT',
    'meanExp',
    'nExp',
    'seExp']

    Challenge

    Before looking below, try to answer some high level questions about the dataset.

    How do we operationalize the question of referees giving more red cards to dark skinned players?

    • Counterfactual: if the player were lighter, a ref is more likely to have given a yellow or no card for the same offense under the same conditions
    • Regression: accounting for confounding, darker players have positive coefficient on regression against proportion red/total card

    Potential issues

    • How to combine rater1 and rater2? Average them? What if they disagree? Throw it out?
    • Is data imbalanced, i.e. red cards are very rare?
    • Is data biased, i.e. players have different amounts of play time? Is this a summary of their whole career?
    • How do I know I've accounted for all forms of confounding?

    First, is there systematic discrimination across all refs?

    Exploration/hypotheses:

    • Distribution of games played
    • red cards vs games played
    • Reds per game played vs total cards per game played by skin color
    • Distribution of # red, # yellow, total cards, and fraction red per game played for all players by avg skin color
    • How many refs did players encounter?
    • Do some clubs play more aggresively and get carded more? Or are more reserved and get less?
    • Does carding vary by leagueCountry?
    • Do high scorers get more slack (fewer cards) for the same position?
    • Are there some referees that give more red/yellow cards than others?
    • how consistent are raters? Check with Cohen's kappa.
    • how do red cards vary by position? e.g. defenders get more?
    • Do players with more games get more cards, and is there difference across skin color?
    • indication of bias depending on refCountry?

    Understand how the data's organized

    The dataset is a single csv where it aggregated every interaction between referee and player into a single row. In other words: Referee A refereed Player B in, say, 10 games, and gave 2 redcards during those 10 games. Then there would be a unique row in the dataset that said:

    Referee A, Player B, 2 redcards, ... 
    
    

    This has several implications that make this first step to understanding and dealing with this data a bit tricky. First, is that the information about Player B is repeated each time -- meaning if we did a simple average of some metric of we would likely get a misleading result.

    For example, asking "what is the average weight of the players?"

    df['height'].mean()
    

    输出 181.93593798236887

    df['height'].mean()
    

    输出 181.93593798236887

    np.mean(df.groupby('playerShort').height.mean())
    

    输出 181.74372848007872

    Tidy Data

    Hadley Wickham's concept of a tidy dataset summarized as:

    • Each variable forms a column
    • Each observation forms a row
    • Each type of observational unit forms a table

    A longer paper describing this can be found in this pdf.

    Having datasets in this form allows for much simpler analyses. So the first step is to try and clean up the dataset into a tidy dataset.

    The first step that I am going to take is to break up the dataset into the different observational units. By that I'm going to have separate tables (or dataframes) for:

    • players
    • clubs
    • referees
    • countries
    • dyads

    Create Tidy Players Table

    df2 = pd.DataFrame({'key1':['a', 'a', 'b', 'b', 'a'],
         'key2':['one', 'two', 'one', 'two', 'one'],
         'data1':np.random.randn(5),
         'data2':np.random.randn(5)})
    df2
    
    grouped = df2['data1'].groupby(df['key1'])
    grouped.mean()
    

    输出:
    key1
    a -0.093686
    b -0.322711
    Name: data1, dtype: float64

    player_index = 'playerShort'
    player_cols = [#'player', # drop player name, we have unique identifier
                   'birthday',
                   'height',
                   'weight',
                   'position',
                   'photoID',
                   'rater1',
                   'rater2',
                  ]
    
    # Count the unique variables (if we got different weight values, 
    # for example, then we should get more than one unique value in this groupby)
    all_cols_unique_players = df.groupby('playerShort').agg({col:'nunique' for col in player_cols})
    
    all_cols_unique_players.head()
    
    # If all values are the same per player then this should be empty (and it is!)
    all_cols_unique_players[all_cols_unique_players > 1].dropna().head()
    
    
    # A slightly more elegant way to test the uniqueness
    all_cols_unique_players[all_cols_unique_players > 1].dropna().shape[0] == 0
    

    输出 True

    def get_subgroup(dataframe, g_index, g_columns):
        
        """Helper function that creates a sub-table from the columns and runs a quick uniqueness test."""
        g = dataframe.groupby(g_index).agg({col:'nunique' for col in g_columns})
        if g[g > 1].dropna().shape[0] != 0:
            print("Warning: you probably assumed this had all unique values but it doesn't.")
        return dataframe.groupby(g_index).agg({col:'max' for col in g_columns})
    
    players = get_subgroup(df, player_index, player_cols)
    players.head()
    
    def save_subgroup(dataframe, g_index, subgroup_name, prefix='raw_'):
        save_subgroup_filename = "".join([prefix, subgroup_name, ".csv.gz"])
        dataframe.to_csv(save_subgroup_filename, compression='gzip', encoding='UTF-8')
        test_df = pd.read_csv(save_subgroup_filename, compression='gzip', index_col=g_index, encoding='UTF-8')
        # Test that we recover what we send in
        if dataframe.equals(test_df):
            print("Test-passed: we recover the equivalent subgroup dataframe.")
        else:
            print("Warning -- equivalence test!!! Double-check.")
    
    players = get_subgroup(df, player_index, player_cols)
    players.head()
    
    save_subgroup(players, player_index, "players")
    

    输出 Test-passed: we recover the equivalent subgroup dataframe.

    Create Tidy Clubs Table

    Create the clubs table.

    club_index = 'club'
    club_cols = ['leagueCountry']
    clubs = get_subgroup(df, club_index, club_cols)
    clubs.head()
    
    clubs['leagueCountry'].value_counts()
    

    输出 :
    England 48
    Spain 27
    France 22
    Germany 21
    Name: leagueCountry, dtype: int64

    save_subgroup(clubs, club_index, "clubs", )
    

    输出 Test-passed: we recover the equivalent subgroup dataframe.

    Create Tidy Referees Table

    referee_index = 'refNum'
    referee_cols = ['refCountry']
    referees = get_subgroup(df, referee_index, referee_cols)
    referees.head()
    
    referees.refCountry.nunique()
    

    输出 161

    referees.tail()
    
    referees.shape
    

    输出 (3147, 1)

    save_subgroup(referees, referee_index, "referees")
    

    输出 Test-passed: we recover the equivalent subgroup dataframe.

    Create Tidy Countries Table

    country_index = 'refCountry'
    country_cols = ['Alpha_3', # rename this name of country
                    'meanIAT',
                    'nIAT',
                    'seIAT',
                    'meanExp',
                    'nExp',
                    'seExp',
                   ]
    countries = get_subgroup(df, country_index, country_cols)
    countries.head()
    
    rename_columns = {'Alpha_3':'countryName', }
    countries = countries.rename(columns=rename_columns)
    countries.head()
    
    countries.shape
    

    输出 (161, 7)

    save_subgroup(countries, country_index, "countries")
    

    输出 Warning -- equivalence test!!! Double-check.

    Create separate (not yet Tidy) Dyads Table

    This is one of the more complex tables to reason about -- so we'll save it for a bit later.

    dyad_index = ['refNum', 'playerShort']
    dyad_cols = ['games',
                 'victories',
                 'ties',
                 'defeats',
                 'goals',
                 'yellowCards',
                 'yellowReds',
                 'redCards',
                ]
    
    dyads = get_subgroup(df, g_index=dyad_index, g_columns=dyad_cols)
    dyads.head()
    
    dyads.shape
    

    输出 (146028, 8)

    dyads[dyads.redCards > 1].head(10)
    
    save_subgroup(dyads, dyad_index, "dyads")
    

    输出 Test-passed: we recover the equivalent subgroup dataframe.

    dyads.redCards.max()
    

    输出 2

    2-Redcard-Players

    %matplotlib inline
    %config InlineBackend.figure_format='retina'
    
    from __future__ import absolute_import, division, print_function
    import matplotlib as mpl
    from matplotlib import pyplot as plt
    from matplotlib.pyplot import GridSpec
    import seaborn as sns
    import numpy as np
    import pandas as pd
    import os, sys
    from tqdm import tqdm
    import warnings
    warnings.filterwarnings('ignore')
    sns.set_context("poster", font_scale=1.3)
    
    import missingno as msno
    import pandas_profiling
    
    from sklearn.datasets import make_blobs
    import time
    
    def save_subgroup(dataframe, g_index, subgroup_name, prefix='raw_'):
        save_subgroup_filename = "".join([prefix, subgroup_name, ".csv.gz"])
        dataframe.to_csv(save_subgroup_filename, compression='gzip', encoding='UTF-8')
        test_df = pd.read_csv(save_subgroup_filename, compression='gzip', index_col=g_index, encoding='UTF-8')
        # Test that we recover what we send in
        if dataframe.equals(test_df):
            print("Test-passed: we recover the equivalent subgroup dataframe.")
        else:
            print("Warning -- equivalence test!!! Double-check.")
    
    def load_subgroup(filename, index_col=[0]):
        return pd.read_csv(filename, compression='gzip', index_col=index_col)
    

    Players

    # players = load_subgroup("../data/redcard/raw_players.csv.gz")
    players = load_subgroup("raw_players.csv.gz")
    
    players.head()
    
    players.shape
    

    输出 (2053, 7)

    Visualize the missing-ness of data

    https://github.com/ResidentMario/missingno

    msno.matrix(players.sample(500),
                figsize=(16, 7),
                width_ratios=(15, 1))
    
    msno.heatmap(players.sample(500),
                figsize=(16, 7),)
    

    ranges from -1 (if one variable appears the other definitely does not) to 0 (variables appearing or not appearing have no effect on one another) to 1 (if one variable appears the other definitely also does).

    print("All players:", len(players))
    print("rater1 nulls:", len(players[(players.rater1.isnull())]))
    print("rater2 nulls:", len(players[players.rater2.isnull()]))
    print("Both nulls:", len(players[(players.rater1.isnull()) & (players.rater2.isnull())]))
    

    输出:
    All players: 2053
    rater1 nulls: 468
    rater2 nulls: 468
    Both nulls: 468

    # modifying dataframe
    players = players[players.rater1.notnull()]
    players.shape[0]
    

    输出 1585

    2053-1585
    

    输出 468
    We've removed 468 players from the table who had no skintone rating.
    Let's look again at the missing data in this table.

    msno.matrix(players.sample(500),
                figsize=(16, 7),
                width_ratios=(15, 1))
    

    Each remaining player in the table has 2 skintone ratings -- are they sufficiently close that they can be combined?

    pd.crosstab(players.rater1, players.rater2)
    
    fig, ax = plt.subplots(figsize=(12, 8))
    sns.heatmap(pd.crosstab(players.rater1, players.rater2), cmap='Blues', annot=True, fmt='d', ax=ax)
    ax.set_title("Correlation between Rater 1 and Rater 2\n")
    fig.tight_layout()
    

    Create useful new columns

    This looks correlated enough to me -- let's combine the rater's skintone ratings into a new column that is the average rating.

    players.head()
    
    # modifying dataframe
    players['skintone'] = players[['rater1', 'rater2']].mean(axis=1)
    players.head()
    

    Visualize distributions of univariate features

    What is the skintone distribution?

    sns.distplot(players.skintone, kde=False);
    

    Positions

    Might the player's position correlate with the baseline susceptibility to redcards? Likely that a defender would have a higher rate than a keeper, for example.

    MIDSIZE = (12, 8)
    fig, ax = plt.subplots(figsize=MIDSIZE)
    players.position.value_counts(dropna=False, ascending=True).plot(kind='barh', ax=ax)
    ax.set_ylabel("Position")
    ax.set_xlabel("Counts")
    fig.tight_layout()
    

    Create higher level categories

    Intuitively, the different positions in the field probably have different redcard rates, but we have data that's very granular.

    Recommendation:

    • create a new column
    • Don't overwrite the original data in case you need it or decide later that the higher level category is not useful

    I chose to split up the position types by their primary roles (you can disagree with my categorization and do it differently if you feel).

    position_types = players.position.unique()
    position_types
    

    输出:
    array(['Center Back', 'Attacking Midfielder', 'Right Midfielder',
    'Center Midfielder', 'Goalkeeper', 'Defensive Midfielder',
    'Left Fullback', nan, 'Left Midfielder', 'Right Fullback',
    'Center Forward', 'Left Winger', 'Right Winger'], dtype=object)

    defense = ['Center Back','Defensive Midfielder', 'Left Fullback', 'Right Fullback', ]
    midfield = ['Right Midfielder', 'Center Midfielder', 'Left Midfielder',]
    forward = ['Attacking Midfielder', 'Left Winger', 'Right Winger', 'Center Forward']
    keeper = 'Goalkeeper'
    
    # modifying dataframe -- adding the aggregated position categorical position_agg
    players.loc[players['position'].isin(defense), 'position_agg'] = "Defense"
    players.loc[players['position'].isin(midfield), 'position_agg'] = "Midfield"
    players.loc[players['position'].isin(forward), 'position_agg'] = "Forward"
    players.loc[players['position'].eq(keeper), 'position_agg'] = "Keeper"
    
    MIDSIZE = (12, 8)
    fig, ax = plt.subplots(figsize=MIDSIZE)
    players['position_agg'].value_counts(dropna=False, ascending=True).plot(kind='barh', ax=ax)
    ax.set_ylabel("position_agg")
    ax.set_xlabel("Counts")
    fig.tight_layout()
    

    Examine pair-wise relationships

    Take a look at measures that will let you quickly see if there are problems or opportunities in the data.

    from pandas.tools.plotting import scatter_matrix
    fig, ax = plt.subplots(figsize=(10, 10))
    scatter_matrix(players[['height', 'weight', 'skintone']], alpha=0.2, diagonal='hist', ax=ax);
    

    Perhaps you want to see a particular relationship more clearly

    fig, ax = plt.subplots(figsize=MIDSIZE)
    sns.regplot('weight', 'height', data=players, ax=ax)
    ax.set_ylabel("Height [cm]")
    ax.set_xlabel("Weight [kg]")
    fig.tight_layout()
    

    There aren't obvious outliers in the height vs weight relationship. Things that I check for:

    • Are there zeros?
    • Are there strange correlations?
    • Are there separate clusters (something that could come from recording the height in inches for some and in cm for others, for example)?

    Create quantile bins for continuous variables

    weight_categories = ["vlow_weight",
                         "low_weight",
                         "mid_weight",
                         "high_weight",
                         "vhigh_weight",
                        ]
    
    players['weightclass'] = pd.qcut(players['weight'],
                                     len(weight_categories),
                                     weight_categories)
    
    players.head()
    
    height_categories = ["vlow_height",
                         "low_height",
                         "mid_height",
                         "high_height",
                         "vhigh_height",
                        ]
    
    players['heightclass'] = pd.qcut(players['height'],
                                     len(height_categories),
                                     height_categories)
    
    print (players['skintone'])
    pd.qcut(players['skintone'], 3)
    

    输出

    playerShort
    aaron-hughes              0.125
    aaron-hunt                0.125
    aaron-lennon              0.250
    aaron-ramsey              0.000
    abdelhamid-el-kaoutari    0.250
    abdou-traore_2            0.750
    abdoulaye-diallo_2        0.875
    abdoulaye-keita_2         0.875
    abdoulwhaid-sissoko       1.000
    adil-rami                 0.125
    adrian-colunga            0.250
    adrian-mutu               0.250
    adrian_2                  0.125
    adrian_7                  0.250
                              ...  
    yoann-gourcuff            0.125
    yohan-cabaye              0.000
    yohandry-orozco           0.500
    yossi-benayoun            0.250
    younes-belhanda           0.250
    younes-kaboul             0.500
    youssef-el-arabi          0.625
    yunus-malli               0.125
    zdenk-pospch              0.125
    zdravko-kuzmanovic        0.000
    ze-castro                 0.250
    zhi-gin-lam               0.250
    zubikarai                 0.000
    zurutuza                  0.000
    Name: skintone, Length: 1585, dtype: float64
    Out[78]:
    playerShort
    aaron-hughes              (-0.001, 0.125]
    aaron-hunt                (-0.001, 0.125]
                                   ...       
    zlatan-alomerovic         (-0.001, 0.125]
    zlatan-ibrahimovic          (0.125, 0.25]
    zlatko-junuzovic          (-0.001, 0.125]
    zoltan-gera                 (0.125, 0.25]
    zoltan-stieber            (-0.001, 0.125]
    zoumana-camara                (0.25, 1.0]
    zubikarai                 (-0.001, 0.125]
    zurutuza                  (-0.001, 0.125]
    Name: skintone, Length: 1585, dtype: category
    Categories (3, interval[float64]): [(-0.001, 0.125] < (0.125, 0.25] < (0.25, 1.0]]
    
    players['skintoneclass'] = pd.qcut(players['skintone'], 3)
    

    Pandas profiling

    There is a library that gives a high level overview -- https://github.com/JosPolfliet/pandas-profiling

    pandas_profiling.ProfileReport(players)
    

    Notice a few things -- it automatically finds highly correlated features -- is that what we want?
    In this case no -- we want the skintone column, and the fact that it's highly correlated with rater1 and rater2, 1, makes sense, but 2, should be consciously selected.

    Question -- What to do with birthday column?

    Some points to consider:

    • this is a career-long dataset of redcards as of 2012-2013 season
    • the age of the player at 2012 does not (necessarily) correspond to the date of receiving a redcard
    players.birthday.head()
    

    输出:
    playerShort
    aaron-hughes 08.11.1979
    aaron-hunt 04.09.1986
    aaron-lennon 16.04.1987
    aaron-ramsey 26.12.1990
    abdelhamid-el-kaoutari 17.03.1990
    Name: birthday, dtype: object

    # modifying dataframe
    players['birth_date'] = pd.to_datetime(players.birthday, format='%d.%m.%Y')
    players['age_years'] = ((pd.to_datetime("2013-01-01") - players['birth_date']).dt.days)/365.25
    players['age_years']
    

    输出

    playerShort
    aaron-hughes              33.149897
    aaron-hunt                26.327173
    aaron-lennon              25.713895
    abdoulwhaid-sissoko       22.787132
    abdul-rahman-baba         18.502396
    abdul-razak               20.139630
                                ...    
    xisco_2                   26.518823
    yacine-brahimi            22.896646
    yann-mvila                22.518823
    zubikarai                 28.848734
    zurutuza                  26.455852
    Name: age_years, Length: 1585, dtype: float64
    

    Select variables to (possibly) use

    players.head()
    
    players_cleaned_variables = players.columns.tolist()
    players_cleaned_variables
    

    输出:
    ['position',
    'rater2',
    'birthday',
    'height',
    'weight',
    'photoID',
    'rater1',
    'skintone',
    'position_agg',
    'weightclass',
    'heightclass',
    'skintoneclass',
    'birth_date',
    'age_years']

    players_cleaned_variables = [#'birthday',
                                 'height',
                                 'weight',
    #                              'position',
    #                              'photoID',
    #                              'rater1',
    #                              'rater2',
                                 'skintone',
                                 'position_agg',
                                 'weightclass',
                                 'heightclass',
                                 'skintoneclass',
    #                              'birth_date',
                                 'age_years']
    pandas_profiling.ProfileReport(players[players_cleaned_variables])
    
    players[players_cleaned_variables].to_csv("cleaned_players.csv.gz", compression='gzip')
    

    Challenge: Do the same process we did above but for the Referee, Clubs, and Country dataframes

    3-Redcard-Dyads

    %matplotlib inline
    %config InlineBackend.figure_format='retina'
    
    from __future__ import absolute_import, division, print_function
    import matplotlib as mpl
    from matplotlib import pyplot as plt
    from matplotlib.pyplot import GridSpec
    import seaborn as sns
    import numpy as np
    import pandas as pd
    import os, sys
    from tqdm import tqdm
    import warnings
    warnings.filterwarnings('ignore')
    sns.set_context("poster", font_scale=1.3)
    
    import missingno as msno
    import pandas_profiling
    
    from sklearn.datasets import make_blobs
    import time
    
    def save_subgroup(dataframe, g_index, subgroup_name, prefix='raw_'):
        save_subgroup_filename = "".join([prefix, subgroup_name, ".csv.gz"])
        dataframe.to_csv(save_subgroup_filename, compression='gzip', encoding='UTF-8')
        test_df = pd.read_csv(save_subgroup_filename, compression='gzip', index_col=g_index, encoding='UTF-8')
        # Test that we recover what we send in
        if dataframe.equals(test_df):
            print("Test-passed: we recover the equivalent subgroup dataframe.")
        else:
            print("Warning -- equivalence test!!! Double-check.")
    
    def load_subgroup(filename, index_col=[0]):
        return pd.read_csv(filename, compression='gzip', index_col=index_col)
    

    Tidy Dyads and Starting Joins

    clean_players = load_subgroup("cleaned_players.csv.gz")
    players = load_subgroup("raw_players.csv.gz", )
    countries = load_subgroup("raw_countries.csv.gz")
    referees = load_subgroup("raw_referees.csv.gz")
    agg_dyads = pd.read_csv("raw_dyads.csv.gz", compression='gzip', index_col=[0, 1])
    
    agg_dyads.head(10)
    

    Test if the number of games is equal to the victories + ties + defeats in the dataset

    all(agg_dyads['games'] == agg_dyads.victories + agg_dyads.ties + agg_dyads.defeats)
    

    输出 True
    Sanity check passes

    len(agg_dyads.reset_index().set_index('playerShort'))
    

    输出 146028

    agg_dyads['totalRedCards'] = agg_dyads['yellowReds'] + agg_dyads['redCards']
    agg_dyads.rename(columns={'redCards': 'strictRedCards'}, inplace=True)
    
    agg_dyads.head()
    

    Remove records that come from players who don't have a skintone rating

    There are a couple of ways to do this -- set operations and joins are two ways demonstrated below:

    clean_players.head()
    
    agg_dyads.head()
    
    agg_dyads.reset_index().head()
    
    agg_dyads.reset_index().set_index('playerShort').head()
    
    player_dyad = (clean_players.merge(agg_dyads.reset_index().set_index('playerShort'),
                                       left_index=True,
                                       right_index=True))
    player_dyad.head()
    
    clean_dyads = (agg_dyads.reset_index()[agg_dyads.reset_index()
                                       .playerShort
                                       .isin(set(clean_players.index))
                                      ]).set_index(['refNum', 'playerShort'])
    clean_dyads.head()
    
    clean_dyads.shape, agg_dyads.shape, player_dyad.shape
    

    输出 ((124621, 9), (146028, 9), (124621, 18))

    Disaggregate

    The dyads are currently an aggregated metric summarizing all times a particular referee-player pair play were matched. To properly handle the data, we have to disaggregate the data into a tidy/long format. This means that each game is a row.

    # inspired by https://github.com/mathewzilla/redcard/blob/master/Crowdstorming_visualisation.ipynb
    colnames = ['games', 'totalRedCards']
    j = 0
    out = [0 for _ in range(sum(clean_dyads['games']))]
    
    for index, row in clean_dyads.reset_index().iterrows():
        n = row['games']
        d = row['totalRedCards']
        ref = row['refNum']
        player = row['playerShort']
        for _ in range(n):
            row['totalRedCards'] = 1 if (d-_) > 0 else 0
            rowlist=list([ref, player, row['totalRedCards']])
            out[j] = rowlist
            j += 1
    
    tidy_dyads = pd.DataFrame(out, columns=['refNum', 'playerShort', 'redcard'],).set_index(['refNum', 'playerShort'])
    
    # 3092
    tidy_dyads.redcard.sum()
    

    输出 3092

    # Notice this is longer than before
    clean_dyads.games.sum()
    

    输出 373067

    tidy_dyads.shape
    

    输出 (373067, 1)

    # Ok, this is a bit crazy... tear it apart and figure out what each piece is doing if it's not clear
    clean_referees = (referees.reset_index()[referees.reset_index()
                                                     .refNum.isin(tidy_dyads.reset_index().refNum
                                                                                           .unique())
                                            ]).set_index('refNum')
    
    clean_referees.shape, referees.shape
    

    输出 ((2978, 1), (3147, 1))

    clean_countries = (countries.reset_index()[countries.reset_index()
                                               .refCountry
                                               .isin(clean_referees.refCountry
                                                     .unique())
                                              ].set_index('refCountry'))
    
    clean_countries.shape, countries.shape
    

    输出 ((160, 7), (161, 7))

    tidy_dyads.head()
    
    tidy_dyads.to_csv("cleaned_dyads.csv.gz", compression='gzip')
    tidy_dyads.shape
    

    4-Redcard-final-joins

    %matplotlib inline
    %config InlineBackend.figure_format='retina'
    
    from __future__ import absolute_import, division, print_function
    import matplotlib as mpl
    from matplotlib import pyplot as plt
    from matplotlib.pyplot import GridSpec
    import seaborn as sns
    import numpy as np
    import pandas as pd
    import os, sys
    from tqdm import tqdm
    import warnings
    warnings.filterwarnings('ignore')
    sns.set_context("poster", font_scale=1.3)
    
    import missingno as msno
    import pandas_profiling
    
    from sklearn.datasets import make_blobs
    import time
    
    # Uncomment one of the following lines and run the cell:
    
    # df = pd.read_csv("redcard.csv.gz", compression='gzip')
    # df = pd.read_csv("https://github.com/cmawer/pycon-2017-eda-tutorial/raw/master/data/redcard/redcard.csv.gz", compression='gzip')
    
    def save_subgroup(dataframe, g_index, subgroup_name, prefix='raw_'):
        save_subgroup_filename = "".join([prefix, subgroup_name, ".csv.gz"])
        dataframe.to_csv(save_subgroup_filename, compression='gzip', encoding='UTF-8')
        test_df = pd.read_csv(save_subgroup_filename, compression='gzip', index_col=g_index, encoding='UTF-8')
        # Test that we recover what we send in
        if dataframe.equals(test_df):
            print("Test-passed: we recover the equivalent subgroup dataframe.")
        else:
            print("Warning -- equivalence test!!! Double-check.")
    
    def load_subgroup(filename, index_col=[0]):
        return pd.read_csv(filename, compression='gzip', index_col=index_col)
    
    clean_players = load_subgroup("cleaned_players.csv.gz")
    players = load_subgroup("raw_players.csv.gz", )
    countries = load_subgroup("raw_countries.csv.gz")
    referees = load_subgroup("raw_referees.csv.gz")
    agg_dyads = pd.read_csv("raw_dyads.csv.gz", compression='gzip', index_col=[0, 1])
    # tidy_dyads = load_subgroup("cleaned_dyads.csv.gz")
    tidy_dyads = pd.read_csv("cleaned_dyads.csv.gz", compression='gzip', index_col=[0, 1])
    

    Joining and further considerations

    clean_players = load_subgroup("cleaned_players.csv.gz")
    temp = tidy_dyads.reset_index().set_index('playerShort').merge(clean_players, left_index=True, right_index=True)
    temp.shape
    

    输出 (373067, 10)

    tidy_dyads.head()
    
    (tidy_dyads.groupby(level=0)
               .sum()
               .sort_values('redcard', ascending=False)
               .rename(columns={'redcard':'total redcards given'})).head()
    
    (tidy_dyads.groupby(level=1)
               .sum()
               .sort_values('redcard', ascending=False)
               .rename(columns={'redcard':'total redcards received'})).head()
    
    tidy_dyads.head()
    
    total_ref_games = tidy_dyads.groupby(level=0).size().sort_values(ascending=False)
    total_player_games = tidy_dyads.groupby(level=1).size().sort_values(ascending=False)
    total_ref_given = tidy_dyads.groupby(level=0).sum().sort_values(ascending=False,by='redcard')
    total_player_received = tidy_dyads.groupby(level=1).sum().sort_values(ascending=False, by='redcard')
    
    sns.distplot(total_player_received, kde=False);
    
    sns.distplot(total_ref_given, kde=False);
    
    tidy_dyads.groupby(level=1).sum().sort_values(ascending=False, by='redcard').head()
    
    tidy_dyads.sum()
    

    输出:
    redcard 3092
    dtype: int64

    tidy_dyads.sum(), tidy_dyads.count(), tidy_dyads.sum()/tidy_dyads.count()
    

    输出:
    (redcard 3092
    dtype: int64, redcard 373067
    dtype: int64, redcard 0.008288
    dtype: float64)

    player_ref_game = (tidy_dyads.reset_index()
                                   .set_index('playerShort')
                                           .merge(clean_players,
                                                  left_index=True,
                                                  right_index=True)
                      )
    player_ref_game.head()
    
    player_ref_game.shape
    

    输出 (373067, 10)

    bootstrap = pd.concat([player_ref_game.sample(replace=True, 
                                                  n=10000).groupby('skintone').mean() 
                           for _ in range(100)])
    player_ref_game.sample(replace=True,n=10000).groupby('skintone').mean()
    
    ax = sns.regplot(bootstrap.index.values,
                     y='redcard',
                     data=bootstrap,
                     lowess=True,
                     scatter_kws={'alpha':0.4,},
                     x_jitter=(0.125 / 4.0))
    ax.set_xlabel("Skintone");
    

    相关文章

      网友评论

          本文标题:探索性数据分析-RedCard-EDA

          本文链接:https://www.haomeiwen.com/subject/vlqsuftx.html