<jupyter_start><jupyter_text>PREPROCESSING<jupyter_code>df = pd.read_csv('deliveries.csv')
df.columns
df2 = pd.read_csv('matches.csv')
df2.columns
df.head()
df2.head()
# To find which stadiums are repeating with a slightly different name
l = sorted([i for i in df2['venue'].unique()])
print(l)
# Correcting stadium names
df2.replace('M. Chinnaswamy Stadium', 'M Chinnaswamy Stadium', inplace=True)
df2.replace('ACA-VDCA Stadium', 'Dr. Y.S. Rajasekhara Reddy ACA-VDCA Cricket Stadium', inplace=True)
df2.replace('Feroz Shah Kotla Ground', 'Feroz Shah Kotla', inplace=True)
df2.replace('Subrata Roy Sahara Stadium', 'Maharashtra Cricket Association Stadium', inplace=True)
df2.replace('M. A. Chidambaram Stadium', 'MA Chidambaram Stadium, Chepauk', inplace=True)
df2.replace('IS Bindra Stadium', 'Punjab Cricket Association IS Bindra Stadium, Mohali', inplace=True)
df2.replace('Punjab Cricket Association Stadium, Mohali', 'Punjab Cricket Association IS Bindra Stadium, Mohali', inplace=True)
df2.replace('Rajiv Gandhi Intl. Cricket Stadium', 'Rajiv Gandhi International Stadium, Uppal', inplace=True)
df2.replace('Dr. Y.S. Rajasekhara Reddy ACA-VDCA Cricket Stadium', 'Dr YS Rajasekhara Reddy ACA VDCA Cricket Stadium', inplace=True)
# Confirming that there are no null values where there shouldn't be any
df.isnull().sum()
df2.isnull().sum()
# The 4 NaN values in winner is because of No Result (due to rain)
# Correcting the date format as it was different for a few seasons
for i in range(len(df2)):
    if df2["season"][i] == 2018 or df2["season"][i] == 2019:
        date = df2["date"][i].split("/")
        date = "20" + date[2] + "-" + date[1] + "-" + date[0]
        df2.loc[i,"date"] = date #updating the format
# Creating the matches dictionary
matches_dict = list()
with open('data.json') as f:
  data = json.load(f)

for k in data.keys():
    for i in data[k].keys():
        winner = data[k][i]["winner"]
        date = data[k][i]["date"]
        venue = data[k][i]["venue"]
        team1 = data[k][i]["team1"]["name"]
        team2 = data[k][i]["team2"]["name"]
        players1 = data[k][i]["team1"]["players"]
        bowler_count_1 = 0
        for j in players1:
            if 'bowlingStyle' in j.keys():
                bowler_count_1 += 1
        batsman_count_1 = 11 - bowler_count_1
        players1 = data[k][i]["team2"]["players"]
        bowler_count_2 = 0
        for j in players1:
            if 'bowlingStyle' in j.keys():
                bowler_count_2 += 1
        batsman_count_2 = 11 - bowler_count_2
        matches_dict.append({"winner" : " ".join(winner.split(" ")[:-4]), \
                          "date": date[:10], "venue": venue, \
                          "team1" : team1, \
                          "bowler_count_1": bowler_count_1, \
                          "batsman_count_1": batsman_count_1, \
                          "team2" : team2, \
                          "bowler_count_2" : bowler_count_2, \
                          "batsman_count_2" : batsman_count_2})
# Correcting the venue/stadium names
new_data = pd.DataFrame(matches_dict)
new_data.replace('ACA-VDCA Stadium', 'Dr YS Rajasekhara Reddy ACA VDCA Cricket Stadium', inplace=True)
new_data.replace('DY Patil Stadium', 'Dr DY Patil Sports Academy', inplace=True)
new_data.replace('Feroz Shah Kotla Ground', 'Feroz Shah Kotla', inplace=True)
new_data.replace('HPCA Stadium', 'Himachal Pradesh Cricket Association Stadium', inplace=True)
new_data.replace('IS Bindra Stadium', 'Punjab Cricket Association IS Bindra Stadium, Mohali', inplace=True)
new_data.replace('JSCA International Cricket Stadium', 'JSCA International Stadium Complex', inplace=True)
new_data.replace('Jawaharlal Nehru Stadium', 'Nehru Stadium', inplace=True)
new_data.replace('M. Chinnaswamy Stadium', 'M Chinnaswamy Stadium', inplace=True)
new_data.replace('M. A. Chidambaram Stadium', 'MA Chidambaram Stadium, Chepauk', inplace=True)
new_data.replace("Maharashtra Cricket Association's International Stadium", 'Maharashtra Cricket Association Stadium', inplace=True)
new_data.replace('Rajiv Gandhi Intl. Cricket Stadium', 'Rajiv Gandhi International Stadium, Uppal', inplace=True)
new_data.replace('Sardar Patel Stadium', 'Sardar Patel Stadium, Motera', inplace=True)
new_data.replace('Zayed Cricket Stadium', 'Sheikh Zayed Stadium', inplace=True)
new_data.replace('Shaheed Veer Narayan Singh International Cricket Stadium', 'Shaheed Veer Narayan Singh International Stadium', inplace=True)
new_data.replace('Vidarbha Cricket Association Stadium', 'Vidarbha Cricket Association Stadium, Jamtha', inplace=True)
new_data
# Creating players dataframe
player_details = pd.DataFrame({})
for i in data.keys():
    for j in data[i].keys():
        y = pd.DataFrame(data[i][j]['team1']['players'])
        player_details = pd.concat([player_details, y])
player_details.drop_duplicates(inplace=True)
player_details.reset_index(inplace=True)
player_details
df2[df2.result=='tie']
# Checking number of tied matches for superovers
abc= df[df['is_super_over']==1].groupby(by='match_id').count()
print(abc)
# Number of superovers played (=7, but there were 9 tied matches)
# Further investigation has to be performed, we can see that match ID 11146 and 11342 have is_super_over=0 in inning=3 and 4
df['inning'].unique()
# innings=5 is wrong
df[((df['inning']==3)|(df['inning']==4)|(df['inning']==5))].groupby(by='inning').count()
# There are 8 balls bowled with inning = 5, should be the ones that are missing with is_super_over=1
for i in range(df.shape[0]):
  if df.iloc[i, 1]==3:
    df.iloc[i, 9]=1  # cleaning: inning=3, is_super_over is made as 1
  elif df.iloc[i,1]==5:
    df.iloc[i,1]=4  # cleaning: inning=5 is made 4
sorted(list(df2.team1.unique()))
# "Rising Pune Supergiants" and "Rising Pune Supergiant" are treated as separate teams like "Delhi Daredevils" and "Delhi Capitals"<jupyter_output><empty_output><jupyter_text>VISUALISATION<jupyter_code># Visualization 1- Head to head analysis of teams
h2h = dict()
def add_to_h2h(team1, team2, winner):
  if team1 in h2h.keys():   #if it is the first time, the team name has appeared as the 'home' team
    if team2 in h2h[team1]:   #if it is the first time, the team name has appeared as the 'away' team
      if winner==team1:
        h2h[team1][team2][0]+=1
      elif winner==team2:
        h2h[team1][team2][2]+=1
      else:
        h2h[team1][team2][1]+=1   #no result matches
    else:  #adding the first record for the away team (vs the home team)
      if winner==team1:
        h2h[team1][team2]=[1,0,0]
      elif winner==team2:
        h2h[team1][team2]=[0,0,1]
      else:
        h2h[team1][team2]=[0,1,0]
  else:  #adding the first record for the home team
    h2h[team1]=dict()
    if winner==team1:
      h2h[team1][team2]=[1,0,0]
    elif winner==team2:
      h2h[team1][team2]=[0,0,1]
    else:
       h2h[team1][team2]=[0,1,0]
for i in range(df2.shape[0]):
  if df2.iloc[i,10] is not None:
    add_to_h2h(df2.iloc[i, 4], df2.iloc[i, 5], df2.iloc[i, 10])
    add_to_h2h(df2.iloc[i, 5], df2.iloc[i, 4], df2.iloc[i, 10])
  else:
    add_to_h2h(df2.iloc[i, 4], df2.iloc[i, 5], df2.iloc[i, 10])

def head_to_head(team):  #this function displays the given team's head-to-head visualization against all other teams
  plt.figure(figsize=(16,10))
  teams=sorted(list(df2.team1.unique()))
  color=['yellow','midnightblue','royalblue','darkblue','orangered','crimson','darkorange','purple','blue','dodgerblue','fuchsia','mediumvioletred','mediumvioletred','red','orange']
  for i in range(len(teams)):
    if teams[i]==team:  #assigning a color to each team (similar to jersey colour)
      team_color=color[i]
      break
  for team2, team2_color in zip(teams, color):
    if team2==team:  #skipping the record of a team against itself since it doesn't make sense
      continue
    if team2 not in h2h[team].keys():
      continue
    t1,nr,t2 = h2h[team][team2]
    t1_ = 100*t1/(t1+nr+t2)  #Win percentage for the given team against the team in the iteration
    nr_ = 100*nr/(t1+nr+t2)  #Percentage of matches between them that ended with No Result
    t2_ = 100*t2/(t1+nr+t2)  #Loss percentage
    plt.barh([team2+'\n'+str(t1)+' '+str(nr)+' '+str(t2)], t1_, color=team_color, height=0.8)
    plt.barh([team2+'\n'+str(t1)+' '+str(nr)+' '+str(t2)], nr_, left=t1_, color='grey', height=0.8)
    plt.barh([team2+'\n'+str(t1)+' '+str(nr)+' '+str(t2)], t2_, left=(t1_+nr_), color=team2_color, height=0.8)
  plt.show()
head_to_head('Royal Challengers Bangalore')
head_to_head('Chennai Super Kings')
# Analysis- Average wickets taken per team over the years
def get_wickets(df, team):
    match_id = 0
    opponents = None
    num_wickets = 0
    wickets = dict()
    for i in range(len(df)):
        if df['bowling_team'][i] == team:
            if match_id == 0:
                match_id = df['match_id'][i]
                opponents = df['batting_team'][i]
            if match_id == df['match_id'][i]:
                if type(df['player_dismissed'][i]) != float:
                    num_wickets += 1
            else:
                if opponents in wickets:
                    wickets[opponents] += [num_wickets]
                else:
                    wickets[opponents] = [num_wickets]
                opponents = df['batting_team'][i]
                match_id = df['match_id'][i]
                num_wickets = 0
                if type(df['player_dismissed'][i]) != float:
                    num_wickets += 1
    for i in wickets:
        wickets[i] = round(np.average(wickets[i]),0)
    return wickets
        
output = dict()
for i in df['batting_team'].unique():
    row = get_wickets(df, i)
    output[i] = row

final_out = pd.DataFrame(output, index = list(df['batting_team'].unique()))
final_out
# Analysis- Average runs scored per team over the years
def get_runs(df, team):
    match_id = 0
    opponents = None
    runs = 0
    run_dict = dict()
    for i in range(len(df)):
        if df['batting_team'][i] == team:
            if match_id == 0:
                match_id = df['match_id'][i]
                opponents = df['bowling_team'][i]
            if match_id == df['match_id'][i]:
                if type(df['total_runs'][i]) != float:
                    runs += df['total_runs'][i]
            else:
                if opponents in run_dict:
                    run_dict[opponents] += [runs]
                else:
                    run_dict[opponents] = [runs]
                opponents = df['bowling_team'][i]
                match_id = df['match_id'][i]
                runs = 0
                if type(df['total_runs'][i]) != float:
                    runs += df['total_runs'][i]
    for i in run_dict:
        run_dict[i] = round(np.average(run_dict[i]),0)
    return run_dict

output = dict()
for i in df['batting_team'].unique():
    row = get_runs(df, i)
    output[i] = row

final_out = pd.DataFrame(output, index = list(df['batting_team'].unique()))
final_out
# Toss Analysis- Win percentage on winning toss for each venue counted over groups, grouped by toss decision  
def toss_win(df, venue):
    match_count = field_count = field_winner_count = bat_count = bat_winner_count = 0
    for i in range(len(df)):
        if df['venue'][i] == venue:
            if df['toss_decision'][i] == 'field':
                field_count += 1
                if df['toss_winner'][i] == df['winner'][i]:
                    field_winner_count += 1
            if df['toss_decision'][i] == 'bat':
                bat_count += 1
                if df['toss_winner'][i] == df['winner'][i]:
                    bat_winner_count += 1
    try:
        field_winner_prob = round(field_winner_count/field_count, 2)
    except:
        field_winner_prob = np.nan
        
    try:
        bat_winner_prob = round(bat_winner_count/bat_count, 2)
    except:
        bat_winner_prob = np.nan
    return({'bat': bat_winner_prob, 'field' : field_winner_prob})

venues = dict()
for i in df2['venue'].unique():
    venues[i] = toss_win(df2, i)
pd.DataFrame(venues).T
# Create a dataset of all players' batting details (those who have batted atleast once) using the ball-by-ball dataset
def get_batting_records(df):
    batsmen = {}
    match=1  #match count being held to see if the batsman remained not out, and to calculate 100s and 50s as we iterate
    for i in range(df.shape[0]):
      if df.iloc[i,6] not in batsmen.keys():
        batsmen[df.iloc[i,6]]={'temp':0, 'temp2':0, 'Runs':0, 'Balls':0, 'Fifties':0, 'Hundreds':0, 'Fours':0, 'Sixes':0, 'Dismissals':0, 'caught':0, 'bowled':0, 'run out':0, 'lbw':0, 'caught and bowled':0, 'stumped':0, 'retired hurt':0, 'hit wicket':0, 'obstructing the field':0, 'Innings':0}
      batsmen[df.iloc[i,6]]['Runs']+=df.iloc[i,15]  #df.iloc[i,6] gives the name of the batsmen
      batsmen[df.iloc[i,6]]['temp']+=df.iloc[i,15]  #2 temporary columns used for calculation of 100s and 50s
      if df.iloc[i,15]==4:
        batsmen[df.iloc[i,6]]['Fours']+=1
      if df.iloc[i,15]==6:
        batsmen[df.iloc[i,6]]['Sixes']+=1

      if df.iloc[i,10]==0 and df.iloc[i,13]==0:
        batsmen[df.iloc[i,6]]['Balls']+=1  #to add 1 ball for each "legal" delivery faced (not a wide or no-ball)
      else:  #note: wides balls are never considered in a batsman's tally
        if df.iloc[i,15]>0 and i+1<df.shape[0] and df.iloc[i,5] != df.iloc[i+1,5]:
          batsmen[df.iloc[i,6]]['Balls']+=1  #to account for no-balls
      if df.iloc[i,13]>0 and i+1<df.shape[0] and df.iloc[i,5] != df.iloc[i+1,5]:
        batsmen[df.iloc[i,6]]['Balls']+=2  #extra if conditions to take care of different format being used to store extras
      elif df.iloc[i,13]>0 and i+1<df.shape[0] and df.iloc[i,5] == df.iloc[i+1,5]:
        batsmen[df.iloc[i,6]]['Balls']+=1

      if df.iloc[i,6]==df.iloc[i,18]:
        batsmen[df.iloc[i,6]]['Dismissals']+=1
        batsmen[df.iloc[i,6]][df.iloc[i,19]]+=1

      if df.iloc[i,0] != batsmen[df.iloc[i,6]]['temp2']:  #to check if match has changed, can update 100s, 50s then
        if batsmen[df.iloc[i,6]]['temp']>=100:
          batsmen[df.iloc[i,6]]['Hundreds']+=1
        elif batsmen[df.iloc[i,6]]['temp']>=50:
          batsmen[df.iloc[i,6]]['Fifties']+=1
        batsmen[df.iloc[i,6]]['temp']=0
        batsmen[df.iloc[i,6]]['temp2'] = df.iloc[i,0]  #updating the new match number into the temp column for the batsman
        batsmen[df.iloc[i,6]]['Innings']+=1
        match=df.iloc[i,0]
    #After iterating fully, we go through the dict and calculate the various metrics such as strike rate, average
    for name in batsmen.keys():
      batsmen[name]['Strike Rate']=(100 * batsmen[name]['Runs'] / batsmen[name]['Balls'])
      if batsmen[name]['Dismissals']>0:
        batsmen[name]['Average']=(batsmen[name]['Runs'] / batsmen[name]['Dismissals'])

    batting_records = pd.DataFrame(batsmen)
    batting_records = batting_records.T
    batting_records.drop(["temp", "temp2"], axis=1, inplace=True)
    batting_records.loc[batting_records.Average.isna() == True , "Average"] = batting_records.Runs / batting_records.Innings  #A fitting used for NaNs (it is an approximation)
    return batting_records

batting_records = get_batting_records(df)
batting_records
# Plotting Dismisssal Analysis
kind=df.groupby('dismissal_kind').count()
t=dict(kind["fielder"][kind.fielder!=0])
plt.bar(t.keys(),t.values())
# Most Caught Dismissal analysis of 10 batsmen dismissal analysis of 10 players in the history of IPL

catch=df[df.dismissal_kind=="caught"].groupby("fielder").count()
f=catch.sort_values(by=["match_id"],ascending=False).head(10)
f1=dict(f["match_id"])
plt.figure(figsize=(20,10))
plt.bar(f1.keys(),f1.values(),width=0.4)
#  Most Stumped Dismissal analysis of 10 batsmen in the history of IPL

stump=df[df.dismissal_kind=="stumped"].groupby("fielder").count()
s=stump.sort_values(by=["match_id"],ascending=False).head(10)
s1=dict(s["match_id"])
plt.figure(figsize=(20,10))
plt.bar(s1.keys(),s1.values())
# Create a dataset of all players' bowling details (those who have bowled atleast once) using the ball-by-ball dataset
def get_bowling_records(df):   
    bowler = {}
    match=1  #similar to batting records above, used to calculate if a bowler took 4 or 5 wicket hauls in thematch
    for i in range(df.shape[0]):
      if df.iloc[i,8] not in bowler.keys():
        bowler[df.iloc[i,8]]={'temp':0, 'temp2':0, 'temp3':0, 'temp4':0, 'Runs':0, 'Balls':0, 'Wickets':0, '4+':0, '5+':0, 'Dots':0, 'Maidens':0, 'Wides':0, 'No balls':0, 'caught':0, 'bowled':0, 'lbw':0, 'caught and bowled':0, 'stumped':0, 'hit wicket':0, 'Innings':0}
      bowler[df.iloc[i,8]]['Runs']+=(df.iloc[i,15]+df.iloc[i,10]+df.iloc[i,13])
      bowler[df.iloc[i,8]]['Wides']+=df.iloc[i,10]
      bowler[df.iloc[i,8]]['No balls']+=df.iloc[i,13]
      if df.iloc[i,17] == 0:
        bowler[df.iloc[i,8]]['Dots']+=1
        bowler[df.iloc[i,8]]['temp4']+=1
      else:
        bowler[df.iloc[i,8]]['temp4']=-200

      if df.iloc[i,10]==0 and df.iloc[i,13]==0:
        bowler[df.iloc[i,8]]['Balls']+=1
      else:
        if df.iloc[i,15]>0 and i+1<df.shape[0] and df.iloc[i,5] != df.iloc[i+1,5]:
          bowler[df.iloc[i,8]]['Balls']+=1  #accounting for no-balls
      if df.iloc[i,13]>0 and i+1<df.shape[0] and df.iloc[i,5] != df.iloc[i+1,5]:
        bowler[df.iloc[i,8]]['Balls']+=2  #extra condition due to different formats used in the dataset
      elif df.iloc[i,13]>0 and i+1<df.shape[0] and df.iloc[i,5] == df.iloc[i+1,5]:
        bowler[df.iloc[i,8]]['Balls']+=1

      if df.iloc[i,19] in ['caught', 'bowled', 'lbw', 'caught and bowled', 'stumped', 'hit wicket']:
        bowler[df.iloc[i,8]]['Wickets']+=1
        bowler[df.iloc[i,8]]['temp']+=1
        bowler[df.iloc[i,8]][df.iloc[i,19]]+=1  #adding the type/kind of wicket the bowler has taken

      if bowler[df.iloc[i,8]]['temp2'] == df.iloc[i,0] and bowler[df.iloc[i,8]]['temp3'] != df.iloc[i,4]:
        if bowler[df.iloc[i,8]]['temp4']==6:  #used to check for maidens, end of each over
          bowler[df.iloc[i,8]]['Maidens']+=1
        bowler[df.iloc[i,8]]['temp4']=0  #set for next over
        bowler[df.iloc[i,8]]['temp3']=df.iloc[i,4]  #setting new over number

      if bowler[df.iloc[i,8]]['temp2'] != df.iloc[i,0]:
        if bowler[df.iloc[i,8]]['temp']>=5:  #used to check for 5 wicket hauls, end of each match
          bowler[df.iloc[i,8]]['5+']+=1
        elif bowler[df.iloc[i,8]]['temp']>=4:  #4 wicket hauls
          bowler[df.iloc[i,8]]['4+']+=1
        bowler[df.iloc[i,8]]['temp']=0  #reset for next over
        bowler[df.iloc[i,8]]['temp2'] = df.iloc[i,0]
        bowler[df.iloc[i,8]]['temp3']=0
        bowler[df.iloc[i,8]]['temp4']=0
        bowler[df.iloc[i,8]]['Innings']+=1
        match=df.iloc[i,0]
    #after iterating through the entire ball-by-ball dataset, we iterate through all the bowlers in the dict to caluclate values for various metrics such as average, economy, strike rate
    for name in bowler.keys():
      bowler[name]['Economy']=(6 * bowler[name]['Runs'] / bowler[name]['Balls'])
      if bowler[name]['Wickets']>0:
        bowler[name]['Strike_Rate']=(bowler[name]['Balls'] / bowler[name]['Wickets'])
        bowler[name]['Average']=(bowler[name]['Runs'] / bowler[name]['Wickets'])

    bowling_records = pd.DataFrame(bowler)
    bowling_records = bowling_records.T
    bowling_records.drop(["temp", "temp2", "temp3", "temp4"], axis=1, inplace=True)
    bowling_records.loc[bowling_records.Strike_Rate.isna() == True , "Strike_Rate"] = bowling_records.Balls
    bowling_records.loc[bowling_records.Average.isna() == True , "Average"] = 999  #Some fixing for the outliers, using 999 instead of infinity (NaN)
    return bowling_records

bowling_records = get_bowling_records(df)
bowling_records
# Checking Bowling economy records
economy=bowling_records.sort_values(by=["Economy"]).head(10)
s1=dict(economy.Economy)
plt.figure(figsize=(20,10))
plt.bar(s1.keys(),s1.values())
'''
strike_rate=batting_records.sort_values(by=['Strike Rate'], ascending=True).head(10)
s2=dict(strike_rate['Strike Rate'])
plt.figure(figsize=(20,10))
plt.bar(s2.keys(),s2.values())
'''
latest_data=pd.merge(df, df2[df2.season>=2018], left_on='match_id', right_on='id', validate='many_to_one')
latest_data.drop(["umpire1","umpire2","umpire3","venue","dl_applied","player_of_match","win_by_wickets","win_by_runs","id"], axis=1, inplace=True)
latest_data.sort_values(by=['match_id', 'inning', 'over', 'ball'],ascending=False)<jupyter_output><empty_output><jupyter_text>BATSMAN RATING<jupyter_code>latest_batting_records = get_batting_records(latest_data)
def get_overall_batting_score(batting_records):    
    df = pd.DataFrame(batting_records["Innings"]).rename(columns = {"Innings" : "matches"})
    df["matches"] = min_max_scaler.fit_transform(df[["matches"]])
    df["achievement_weight"] = 20 * batting_records["Hundreds"] + 10 * batting_records["Fifties"] + 3 * batting_records["Sixes"] + batting_records["Fours"]
    df["stat_score"] = df["achievement_weight"]*0.3 + batting_records["Average"]*0.55 + batting_records["Strike Rate"]*0.15
    df["overall_score"] = df["stat_score"] * df["matches"]
    return df.sort_values(by=["overall_score", "matches", "achievement_weight", "stat_score"])
def get_batsman_rating(batting_records, latest_batting_records):
    overall_score = get_overall_batting_score(batting_records)
    latest_score = get_overall_batting_score(latest_batting_records)
    batsman_rating = pd.merge(overall_score[["overall_score"]], latest_score[["overall_score"]], how="outer", left_index=True, right_index=True, suffixes=["_career", "_latest"]).fillna(0)
    batsman_rating["batsman_rating"] = 0.4*batsman_rating["overall_score_career"] + 0.6*batsman_rating["overall_score_latest"]
    batsman_rating["batsman_rating"] = min_max_scaler.fit_transform(batsman_rating[["batsman_rating"]]) * 100
    return batsman_rating[["batsman_rating"]].sort_values(by=["batsman_rating"], ascending=False)
batsman_rating = get_batsman_rating(batting_records, latest_batting_records)
batsman_rating<jupyter_output><empty_output><jupyter_text>BOWLER RATING<jupyter_code>latest_bowling_records = get_bowling_records(latest_data)
def get_overall_bowling_score(bowling_records):    
    df = pd.DataFrame(bowling_records["Innings"]).rename(columns = {"Innings" : "matches"})
    df["matches"] = min_max_scaler.fit_transform(df[["matches"]])
    df["achievement_weight"] = 5 * bowling_records["Maidens"] + bowling_records["Dots"]
    df["wicket_weight"] = 30 * bowling_records["5+"] + 20 * bowling_records["4+"] + 10 * bowling_records["Wickets"]
    df["stat_score"] = bowling_records["Average"] + bowling_records["Economy"] + 1 / (1+df["achievement_weight"])
    df["overall_score"] = (df["wicket_weight"] * df["matches"]) / df["stat_score"]
    return df.sort_values(by=["overall_score", "matches", "achievement_weight", "stat_score"])
def get_bowler_rating(bowling_records, latest_bowling_records):
    overall_score = get_overall_bowling_score(bowling_records)
    max_overall = overall_score["overall_score"].max()
    overall_score["overall_score"] = overall_score["overall_score"] / max_overall
    latest_score = get_overall_bowling_score(latest_bowling_records)
    max_latest = latest_score["overall_score"].max()
    latest_score["overall_score"] = latest_score["overall_score"] / max_latest
    bowler_rating = pd.merge(overall_score[["overall_score"]], latest_score[["overall_score"]], how="outer", left_index=True, right_index=True, suffixes=["_career", "_latest"]).fillna(0)
    bowler_rating["bowler_rating"] = 0.35*bowler_rating["overall_score_career"] + 0.65*bowler_rating["overall_score_latest"]
    bowler_rating["bowler_rating"] = min_max_scaler.fit_transform(bowler_rating[["bowler_rating"]]) * 100
    return bowler_rating[["bowler_rating"]].sort_values(by=["bowler_rating"], ascending=False)
bowler_rating = get_bowler_rating(bowling_records, latest_bowling_records)
bowler_rating<jupyter_output><empty_output><jupyter_text>PLAYING 11 SELECTION USING DISTANCES<jupyter_code>given_team = ["SP Narine", "<NAME>", "<NAME>", "<NAME>", \
              "<NAME>", "<NAME>", "<NAME>", "<NAME>", \
              "<NAME>", "<NAME>", "<NAME>", "<NAME>", "<NAME>", \
             "MP Stoinis", "DA Miller"]
given_team = pd.DataFrame(data={"Players": given_team})
def select_playing_11_euclidian(given_team, batsman_rating, bowler_rating):
    temp = pd.merge(given_team, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    temp2 = temp.apply(lambda x: temp.loc[~x.isin(selected_team[x.name]),x.name]).fillna(0)
    euclid_distance = dict()
    for i in temp2.index:
        dist = ((100 - temp2.batsman_rating[i])**2 + (100 - temp2.bowler_rating[i])**2)**0.5
        euclid_distance[temp2["Players"][i]] = dist
    rest_5 = pd.DataFrame((list(euclid_distance.items()))).rename(columns = {0:"Players", 1:"Euclid_Distance"}).sort_values(by=["Euclid_Distance"])[["Players"]].head(5)
    selected_team = pd.concat([selected_team[["Players"]], rest_5]).reset_index(drop=True)
    selected_team = pd.merge(temp, selected_team, how="right")
    return selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
select_playing_11_euclidian(given_team, batsman_rating, bowler_rating)
def select_playing_11_city_block(given_team, batsman_rating, bowler_rating):
    temp = pd.merge(given_team, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    temp2 = temp.apply(lambda x: temp.loc[~x.isin(selected_team[x.name]),x.name]).fillna(0)
    city_block = dict()
    for i in temp2.index:
        dist = abs(100 - temp2.batsman_rating[i]) + abs(100 - temp2.bowler_rating[i])
        city_block[temp2["Players"][i]] = dist
    rest_5 = pd.DataFrame((list(city_block.items()))).rename(columns = {0:"Players", 1:"city_block_distance"}).sort_values(by=["city_block_distance"])[["Players"]].head(5)
    selected_team = pd.concat([selected_team[["Players"]], rest_5])
    selected_team = pd.merge(temp, selected_team, how="right")
    return selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
select_playing_11_city_block(given_team, batsman_rating, bowler_rating)
def select_playing_11_cosine(given_team, batsman_rating, bowler_rating):
    temp = pd.merge(given_team, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    temp2 = temp.apply(lambda x: temp.loc[~x.isin(selected_team[x.name]),x.name]).fillna(0)
    cosine_dist = dict()
    for i in temp2.index:
        bat = temp2.batsman_rating[i]
        bowl = temp2.bowler_rating[i]
        similarity = (100*bat + 100*bowl)/(((100**2 + bat**2)**0.5) * ((100**2 + bowl**2)**0.5))
        cosine_dist[temp2["Players"][i]] = 1 - similarity
    rest_5 = pd.DataFrame((list(cosine_dist.items()))).rename(columns = {0:"Players", 1:"Cosine_Distance"}).sort_values(by=["Cosine_Distance"])[["Players"]].head(5)
    selected_team = pd.concat([selected_team[["Players"]], rest_5])
    selected_team = pd.merge(temp, selected_team, how="right")
    return selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
select_playing_11_cosine(given_team, batsman_rating, bowler_rating)
def select_playing_11_chebychev(given_team, batsman_rating, bowler_rating):
    temp = pd.merge(given_team, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    temp2 = temp.apply(lambda x: temp.loc[~x.isin(selected_team[x.name]),x.name]).fillna(0)
    chebychev_dist = dict()
    for i in temp2.index:
        bat = temp2.batsman_rating[i]
        bowl = temp2.bowler_rating[i]
        chebychev_dist[temp2["Players"][i]] = max(abs(100-bat), abs(100-bowl))
    rest_5 = pd.DataFrame((list(chebychev_dist.items()))).rename(columns = {0:"Players", 1:"chebychev_dist"}).sort_values(by=["chebychev_dist"])[["Players"]].head(5)
    selected_team = pd.concat([selected_team[["Players"]], rest_5])
    selected_team = pd.merge(temp, selected_team, how="right")
    return selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
select_playing_11_chebychev(given_team, batsman_rating, bowler_rating)
def select_playing_11_canberra(given_team, batsman_rating, bowler_rating):
    temp = pd.merge(given_team, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    temp2 = temp.apply(lambda x: temp.loc[~x.isin(selected_team[x.name]),x.name]).fillna(0)
    canberra_dist = dict()
    for i in temp2.index:
        bat = temp2.batsman_rating[i]
        bowl = temp2.bowler_rating[i]
        canberra_dist[temp2["Players"][i]] = abs(bat - bowl)/abs(bat + bowl)
    rest_5 = pd.DataFrame((list(canberra_dist.items()))).rename(columns = {0:"Players", 1:"canberra_dist"}).sort_values(by=["canberra_dist"])[["Players"]].head(5)
    selected_team = pd.concat([selected_team[["Players"]], rest_5])
    selected_team = pd.merge(temp, selected_team, how="right")
    return selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
select_playing_11_canberra(given_team, batsman_rating, bowler_rating)<jupyter_output><empty_output><jupyter_text>TOSS DECISION<jupyter_code>def bat_or_field(match_data, team1, team2, venue):
    toss_decision = df2[["team1", "team2", "toss_winner", "toss_decision", "winner", "venue"]]
    toss_decision = toss_decision[(toss_decision["team1"] == team1) | (toss_decision["team2"] == team1)]
    toss_decision_1 = toss_decision[(toss_decision["team1"] == team2) | (toss_decision["team2"] == team2)]
    toss_decision_1 = toss_decision_1[toss_decision_1["toss_winner"] == team1]
    toss_decision_1 = toss_decision_1[toss_decision_1["venue"] == venue]
    toss_decision_2 = toss_decision[toss_decision["toss_winner"] == team1]
    toss_decision_2 = toss_decision_2[toss_decision_2["venue"] == venue]
    toss_decision_2 = toss_decision_2[toss_decision_2["winner"] == team1]
    
    try:
        bat_1 = toss_decision_1.groupby(["toss_decision", "winner"]).size()["bat"][team1]
    except:
        bat_1 = 0
    try:
        field_1 = toss_decision_1.groupby(["toss_decision", "winner"]).size()["field"][team1]
    except:
        field_1 = 0

    try:
        bat_2 = toss_decision_2.groupby(["toss_decision", "winner"]).size()["bat"][team1]
    except:
        bat_2 = 0
    try:
        field_2 = toss_decision_2.groupby(["toss_decision", "winner"]).size()["field"][team1]
    except:
        field_2 = 0
    bat = 0.6 * bat_1 + 0.4 * bat_2
    field = 0.6 * field_1 + 0.4 * field_2
    if bat > field:
        print("Bat")
    else:
        print("Field")
team1 = "<NAME>"
team2 = "<NAME>"
venue = "M Chinnaswamy Stadium"
bat_or_field(df2, team1, team2, venue)<jupyter_output>Field<jupyter_text>FINAL TEAM SELECTION<jupyter_code>def get_stadium_bias(data, venue):
    bat = 0
    bowl = 0
    count = 0
    for i in range(len(data)):
        if data["venue"][i] == venue:
            count += 1
            if data["winner"][i] == data["team1"][i]:
                bat += data["batsman_count_1"][i]
                bowl += data["bowler_count_1"][i]
            else:
                bat += data["batsman_count_2"][i]
                bowl += data["bowler_count_2"][i]
    return (round(bowl/count), round(bat/count))
get_stadium_bias(new_data, 'M Chinnaswamy Stadium')
def latest_team_selecter(given_team, batsman_rating, bowler_rating, data, player_details, venue):
    #finding nationality of each player
    team_details = list()
    for i in range(len(given_team)):
        for j in range(len(player_details)):
            if set(player_details['shortName'][j]).issuperset(given_team['Players'][i]) or set(given_team['Players'][i]).issuperset(player_details['shortName'][j]):
                team_details.append({'Players': given_team['Players'][i], 'Nationality': player_details['nationality'][j]})
                break
    team_deatils = pd.DataFrame(team_details)
    
    #merging details, batting and bowling rankings
    temp = pd.merge(team_deatils, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)
    
    #selecting top 6 players(top 3 each)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)
    
    #seeing who's not selected yet
    temp2 = temp.merge(selected_team.drop_duplicates(), on=['Players', 'Nationality', 'batsman_rating', 'bowler_rating'], how='left', indicator=True)
    temp2 = temp2[temp2['_merge'] == 'left_only'].drop(columns='_merge')
    
    #checking if we should have more bowlers than batsmen
    bowler_bias, batsman_bias = get_stadium_bias(new_data, venue)
    bowlers = 3 if bowler_bias > batsman_bias else 2
    batsmen = 3 if bowler_bias < batsman_bias else 2
    
    #accodingly select the remaining 5 players
    remaining_bowlers = temp2.sort_values(by="bowler_rating", ascending=False).head(int(bowlers))
    remaining_batsmen = temp2.sort_values(by="batsman_rating", ascending=False).head(int(batsmen))
    selected_team = pd.merge(selected_team, remaining_batsmen, how="outer")
    selected_team = pd.merge(selected_team, remaining_bowlers, how="outer")
    selected_team = selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
    
    return selected_team
latest_team_selecter(given_team, batsman_rating, bowler_rating, new_data, player_details, venue="M Chinnaswamy Stadium")
def final_team_selecter(given_team, batsman_rating, bowler_rating, new_data, player_details, venue):
    team_details = list()
    for i in range(len(given_team)):
        for j in range(len(player_details)):
            if set(player_details['shortName'][j]).issuperset(given_team['Players'][i]) or set(given_team['Players'][i]).issuperset(player_details['shortName'][j]):
                team_details.append({'Players': given_team['Players'][i], 'Nationality': player_details['nationality'][j]})
                break
    team_deatils = pd.DataFrame(team_details)

    #merging details, batting and bowling rankings
    temp = pd.merge(team_deatils, batsman_rating, left_on="Players", right_index=True)
    temp = pd.merge(temp, bowler_rating, left_on="Players", right_index=True, how="left").fillna(0).reset_index(drop=True)

    #selecting top 6 players(top 3 each)
    top_3_bowlers = temp.sort_values(by=["bowler_rating", "batsman_rating"], ascending=False).head(3)
    top_3_batsman = temp.sort_values(by=["batsman_rating", "bowler_rating"], ascending=False).head(3)
    selected_team = pd.concat([top_3_batsman, top_3_bowlers]).reset_index(drop=True)

    #seeing who's not selected yet
    temp2 = temp.merge(selected_team.drop_duplicates(), on=['Players', 'Nationality', 'batsman_rating', 'bowler_rating'], how='left', indicator=True)
    temp2 = temp2[temp2['_merge'] == 'left_only'].drop(columns='_merge')

    #using the euclidian distacnce from perfect player to see all rounders
    euclid_distance =list()
    for i in temp2.index:
        dist = ((100 - temp2.batsman_rating[i])**2 + (100 - temp2.bowler_rating[i])**2)**0.5
        euclid_distance.append({"Players" : temp2["Players"][i], \
                                "Nationality" : temp2["Nationality"][i], \
                               "batsman_rating": temp2["batsman_rating"][i], \
                               "bowler_rating": temp2["bowler_rating"][i], \
                               "euclid_distance": dist})
    euclid_distance = pd.DataFrame(euclid_distance)

    #checking if we should have more bowlers than batsmen
    bowler_bias, batsman_bias = get_stadium_bias(new_data, venue)
    if bowler_bias >= 7:
        bowlers = 4
        batsmen = 1
    elif batsman_bias >= 7:
        bowlers = 1
        batsmen = 4
    else:
        bowlers = bowler_bias - 3
        batsmen = batsman_bias - 3

    #choosing top 3 all rounders with high bowler/batsman rating respectively
    remaining_bowlers = euclid_distance.query("bowler_rating > batsman_rating").sort_values(by="euclid_distance").head(int(bowlers))
    remaining_batsmen = euclid_distance.query("bowler_rating < batsman_rating").sort_values(by="euclid_distance").head(int(batsmen))
    selected_team = pd.merge(selected_team, remaining_batsmen, how="outer")
    selected_team = pd.merge(selected_team, remaining_bowlers, how="outer")
    selected_team = selected_team.sort_values(by="batsman_rating", ascending=False).reset_index(drop=True)
    return selected_team[["Players", "Nationality", "batsman_rating", "bowler_rating"]]
final_team_selecter(given_team, batsman_rating, bowler_rating, new_data, player_details, venue="M Chinnaswamy Stadium")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.15738498789346247, 'fraction_numerical': 0.025011591365720467, 'mean_word_length': 4.392083333333333, 'pattern_counts': {'":': 8, '<': 50, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '44758', 'license': 'MIT', 'n_tokens_mistral': 14661, 'n_tokens_neox': 14012, 'n_words': 2607, 'path': 'Code/DA_Project.ipynb', 'repo_name': 'Lavitra15/DataAnalytics-Project', 'size': '38890'}