이전 포스팅에서 이어지는 내용이므로 꼭 보고 오는 것을 추천한다.
2021.04.15 - [University] - [ Python Project ] EPL 데이터 분석을 통한 토트넘의 현실 - 1
저번 포스팅에서 토트넘의 현재 순위까지 알아보았었다.
4월 5일 기준(30R)으로 7등이었고, 골득실로 보았을 때는 5등에 위치하였다.
여기서 궁금증이 생겼는데,
우승을 하기 위해서는 어느 정도의 승점이 필요하고, 어느정도의 골과 슈팅이 필요할까?
이번 포스팅은 이 궁금증을 해결하고 결론으로 마무리 될 예정이다.
[ 우승팀 / 강등팀의 승점 ]
[ 우승팀의 승점 / 분석 ]
각 시즌마다 우승팀을 뽑아보기 위해 시즌마다 순위를 정리해주었다.
# 시즌 list
season=list(EPL_data['Season'].unique())
한번에 처리하기 위해 season 리스트를 만들어주었다.
for count,i in enumerate(season,1994):
rank = {}
s=EPL_data.loc[EPL_data['Season']==i,:] # 시즌별로 추출
for j in s.index:
if s['FTR'][j]=='H': # 홈팀 승리
if s['HomeTeam'][j] in rank: # 딕셔너리 안에 있으면 추가
rank[s['HomeTeam'][j]] = rank[s['HomeTeam'][j]]+ 3
else:
rank[s['HomeTeam'][j]] = 3
elif s['FTR'][j]=='D': # 동점
if s['HomeTeam'][j] in rank: # 딕셔너리 안에 있으면 추가
rank[s['HomeTeam'][j]] = rank[s['HomeTeam'][j]]+ 1
else:
rank[s['HomeTeam'][j]] = 1
if s['AwayTeam'][j] in rank: # 딕셔너리 안에 있으면 추가
rank[s['AwayTeam'][j]] = rank[s['AwayTeam'][j]]+ 1
else:
rank[s['AwayTeam'][j]] = 1
else: # 어웨이팀 승리
if s['AwayTeam'][j] in rank: # 딕셔너리 안에 있으면 추가
rank[s['AwayTeam'][j]] = rank[s['AwayTeam'][j]]+ 3
else:
rank[s['AwayTeam'][j]] = 3
df = pd.DataFrame(list(rank.items()), columns=['TEAM', 'Point'])
df=df.sort_values(by='Point',ascending=False)
df= df.reset_index(drop=True)
df.index = df.index + 1
df["season"] = count
globals()["s_"+str(count)] = df
처음으로 enumerate 라는 함수를 사용해보았다.
zip과 비슷한 역할을 하고 1개 반복문의 다수의 변수를 넣을 수 있다는 장점이 있다.
season 별로 loc를 뽑아서 한 행씩 처리를 한다.
홈팀이 승리 했을 경우 / 어웨이 팀이 승리 했을 경우 / 동점인 경우 - 3가지로 나눠서 처리했다.
EPL 시스템에서는 이기면 승점 3점이고 지면 0점 동점이면 1점이다.
그리고 계속 누적을 해야했기에 딕셔너리 안에 있으면 초기화가 안되고 누적되는 방법을 이용했다.
그 딕셔너리를 DataFrame으로 만들어 승점별로 내림차순을 하여 보기 쉽게 인덱스를 초기화 해주었고,
globals를 이용해 동적으로 변수가 생성되게 만들었다.
concat을 통해 각 DataFrame을 통합하면 이러하다.
전체를 concat을 한 후 index가 1인 즉, 그 시즌에서 우승팀들만 뽑아보았다.
total=pd.concat([s_1994,s_1995,s_1996,s_1997,s_1998,s_1999,s_2000,s_2001,s_2002,s_2003,s_2004,s_2005,s_2006,s_2007,s_2008,s_2009,s_2010,s_2011,s_2012,s_2013,s_2014,s_2015,s_2016,s_2017,s_2018,s_2019,s_2020,], axis=0)
best_season=total[total.index==1]
우승팀의 count를 뽑아보면 이러하다.
위에 DataFrame에서도 볼 수 있듯이 맨체스터 유나이티드의 압도적인 우승 횟수를 볼 수있다.
각 우승팀의 승점을 알아보고 분석을 하기 위해 시각화와 여러 통계자료를 만들어보았다.
이 시각화와 통계자료를 보고 생각을 해보았다.
통계자료에서 중요하게 본 것은 최솟값과 중앙값, 평균이다.
min은 최소 승점이 75점은 되어야 우승을 할 가능성이 있다는 것을 보여준다.
( 현재 토트넘은 30경기 49점이며 8경기 남은 상태 )
( 전승을 한다고 하여도 49+(8x3) = 73점... 우승은 가능성없다.)
mean과 50%(중앙값)에서 보여주는 것은 승점이 87점~89점 정도 되면 우승이라는 수치를 보여준다.
[ 강등팀의 승점 / 분석 ]
강등팀도 우승팀과 마찬가지로 한 DataFrame으로 모아보았다.
강등을 할 수 있는 조건을 보는 것이기 때문에
강등팀중에서 높은 승점으로 떨어지는 팀들만 모았다. (아슬아슬하게 커트라인으로 강등되는 팀들)
lo_1=pd.concat([s_1996,s_1997,s_1998,s_1999,s_2000,s_2001,s_2002,s_2003,s_2004,s_2005,s_2006,s_2007,s_2008,s_2009,s_2010,s_2011,s_2012,s_2013,s_2014,s_2015,s_2016,s_2017,s_2018,s_2019,s_2020,], axis=0)
lo_2=s_1994[s_1994.index==20]
lo_3=s_1995[s_1995.index==19]
lo_1=lo_1[lo_1.index==18]
lo_total=pd.concat([lo_1,lo_2,lo_3],axis=0)
lo_total=lo_total.sort_values(by='season',ascending=False)
우승팀에서 모았던 것과 다른점이 있을텐데,
일단 93-94시즌에는 20, 21, 22 등이 강등을 했고,
94-95시즌에는 19,20,21,22 등이 강등을 했다.
그 후로는 18,19,20 등만 강등을 해서 저렇게 분할하여 concat를 하였다.
이 DataFrame을 토대로하여 우승팀처럼 count와 시각화, 통계분석을 해보았다.
여기서도 아까 우승팀처럼 나름의 분석을 해보자면
mean와 50%를 보았을 때, 승점이 36점정도 되면 강등할 가능성이 크다는 것을 알 수있다.
이렇게 우승팀과 강등팀의 승점과 나름의 분석을 해보았다.
다음은 우승팀들의 공통점이 무엇인지.. 공격력과 수비력 측면에서 살펴보겠다.
[ 우승하는 팀들의 공통점 (공격력, 수비력 측면) ]
[ 공격력 ]
공격력은 득점과 슈팅 수 , 유효 슈팅 수로 살펴보았다.
득점부터 코딩을 해보았다.
best_team=list(best_season['TEAM'])
count =1994
for s,t in zip(season,best_team):
b_goal = {}
s_data=EPL_data.loc[(EPL_data['Season']==s),:]
s_data=s_data.loc[(s_data['HomeTeam']==t)|(s_data['AwayTeam']==t),:]
for j in s_data.index:
#득점
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_goal: # 홈팀에서 골
b_goal[s_data['HomeTeam'][j]] = b_goal[s_data['HomeTeam'][j]]+ s_data['FTHG'][j]
else:
b_goal[s_data['HomeTeam'][j]] = s_data['FTHG'][j]
elif s_data['AwayTeam'][j]==t: # 어웨이 팀일때
if s_data['AwayTeam'][j] in b_goal: # 어웨이팀에서 골
b_goal[s_data['AwayTeam'][j]] = b_goal[s_data['AwayTeam'][j]]+ s_data['FTAG'][j]
else:
b_goal[s_data['AwayTeam'][j]] = s_data['FTAG'][j]
df = pd.DataFrame(list(b_goal.items()), columns=['TEAM', 'Goal'])
df["season"] = count
globals()["b_"+str(count)] = df
count += 1
슈팅과 유효슈팅은 데이터 유실로 인해 2000-01 시즌부터 있기 때문에 따로 뽑았다.
# 슈팅
# 유효슈팅
best_team=list(best_season['TEAM'])
count =2001
for s,t in zip(season,best_team):
b_shot = {}
b_shot_target = {}
s_data=EPL_data.loc[(EPL_data['Season']==s),:]
s_data=s_data.loc[(s_data['HomeTeam']==t)|(s_data['AwayTeam']==t),:]
for j in s_data.index:
#슈팅
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_shot: # 홈팀에서 슈팅
b_shot[s_data['HomeTeam'][j]] = b_shot[s_data['HomeTeam'][j]]+ s_data['HS'][j]
else:
b_shot[s_data['HomeTeam'][j]] = s_data['HS'][j]
elif s_data['AwayTeam'][j] == t: # 어웨팀일 때
if s_data['AwayTeam'][j] in b_shot: # 홈팀에서 슈팅
b_shot[s_data['AwayTeam'][j]] = b_shot[s_data['AwayTeam'][j]]+ s_data['AS'][j]
else:
b_shot[s_data['AwayTeam'][j]] = s_data['AS'][j]
# 유효슈팅
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_shot_target: # 홈팀에서 슈팅
b_shot_target[s_data['HomeTeam'][j]] = b_shot_target[s_data['HomeTeam'][j]]+ s_data['HST'][j]
else:
b_shot_target[s_data['HomeTeam'][j]] = s_data['HST'][j]
elif s_data['AwayTeam'][j] == t: # 어웨팀일 때
if s_data['AwayTeam'][j] in b_shot_target: # 홈팀에서 슈팅
b_shot_target[s_data['AwayTeam'][j]] = b_shot_target[s_data['AwayTeam'][j]]+ s_data['AST'][j]
else:
b_shot_target[s_data['AwayTeam'][j]] = s_data['AST'][j]
df = pd.DataFrame(list(b_shot.items()), columns=['TEAM', 'Shot'])
df_f = pd.DataFrame(list(b_shot_target.items()), columns=['TEAM', 'Shot_target'])
t_df = pd.merge(df,df_f,on='TEAM')
t_df["season"] = count
globals()["b_s_"+str(count)] = t_df
count += 1
기본적인 매커니즘은 승점뽑아내는 것과 비슷하다.
그래서 모아보면 이러한 DataFrame 값이 나온다.
주석에도 나와있듯이 mean 값들을 보아
우승팀의 공격력은 경기당 2골정도 넣고, 14번의 슈팅으로 7번의 유효슈팅 하는 것을 알 수 있다.
역시 우승팀이라서 그런지 굉장히 높은 수치이다.
[ 수비력 ]
수비력은 실점과 파울 수, 경고, 퇴장을 뽑아보았다.
경고와 퇴장이 수비력과 큰 상관이 있는지는 모르겠다.
수비력에 대한 마땅한 데이터가 없어서 일단 넣긴 했다.
count =1994
for s,t in zip(season,best_team):
b_aga = {}
s_data=EPL_data.loc[(EPL_data['Season']==s),:]
s_data=s_data.loc[(s_data['HomeTeam']==t)|(s_data['AwayTeam']==t),:]
for j in s_data.index:
#실점
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_aga: # 홈에서 실점
b_aga[s_data['HomeTeam'][j]] = b_aga[s_data['HomeTeam'][j]]+ s_data['FTAG'][j]
else:
b_aga[s_data['HomeTeam'][j]] = s_data['FTAG'][j]
elif s_data['AwayTeam'][j]==t: # 어웨이 팀일때
if s_data['AwayTeam'][j] in b_aga: # 어웨이에서 실점
b_aga[s_data['AwayTeam'][j]] = b_aga[s_data['AwayTeam'][j]]+ s_data['FTHG'][j]
else:
b_aga[s_data['AwayTeam'][j]] = s_data['FTHG'][j]
df = pd.DataFrame(list(b_aga.items()), columns=['TEAM', 'Goal_Against'])
df["season"] = count
globals()["b_a_"+str(count)] = df
count += 1
실점에 대한 코딩이다. 득점과 큰 차이점은 없다. (홈팀일 때 어웨이 골이랑 어웨이팀일 때 홈 골 - 이 차이일 뿐)
# 파울
# 카드 수 (옐로, 레드)
best_team=list(best_season['TEAM'])
best_team = best_team[7:]
season = season[7:]
count =2001
for s,t in zip(season,best_team):
b_foul = {}
b_y_card = {}
b_r_card = {}
s_data=EPL_data.loc[(EPL_data['Season']==s),:]
s_data=s_data.loc[(s_data['HomeTeam']==t)|(s_data['AwayTeam']==t),:]
for j in s_data.index:
#파울
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_foul: # 홈에서 파울
b_foul[s_data['HomeTeam'][j]] = b_foul[s_data['HomeTeam'][j]]+ s_data['HF'][j]
else:
b_foul[s_data['HomeTeam'][j]] = s_data['HF'][j]
elif s_data['AwayTeam'][j] == t: # 어웨팀일 때
if s_data['AwayTeam'][j] in b_foul: # 어웨이일 때 파울
b_foul[s_data['AwayTeam'][j]] = b_foul[s_data['AwayTeam'][j]]+ s_data['AF'][j]
else:
b_foul[s_data['AwayTeam'][j]] = s_data['AF'][j]
# 옐로 카드
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_y_card: # 홈에서 옐로 카드
b_y_card[s_data['HomeTeam'][j]] = b_y_card[s_data['HomeTeam'][j]]+ s_data['HY'][j]
else:
b_y_card[s_data['HomeTeam'][j]] = s_data['HY'][j]
elif s_data['AwayTeam'][j] == t: # 어웨팀일 때
if s_data['AwayTeam'][j] in b_y_card: # 어웨이일 때 옐로 카드
b_y_card[s_data['AwayTeam'][j]] = b_y_card[s_data['AwayTeam'][j]]+ s_data['AY'][j]
else:
b_y_card[s_data['AwayTeam'][j]] = s_data['AY'][j]
# 레드 카드
if s_data['HomeTeam'][j] == t: # 홈팀일 때
if s_data['HomeTeam'][j] in b_r_card: # 홈에서 레드 카드
b_r_card[s_data['HomeTeam'][j]] = b_r_card[s_data['HomeTeam'][j]]+ s_data['HR'][j]
else:
b_r_card[s_data['HomeTeam'][j]] = s_data['HR'][j]
elif s_data['AwayTeam'][j] == t: # 어웨팀일 때
if s_data['AwayTeam'][j] in b_r_card: # 어웨이일 때 레드 카드
b_r_card[s_data['AwayTeam'][j]] = b_r_card[s_data['AwayTeam'][j]]+ s_data['AR'][j]
else:
b_r_card[s_data['AwayTeam'][j]] = s_data['AR'][j]
df_1 = pd.DataFrame(list(b_foul.items()), columns=['TEAM', 'foul'])
df_2 = pd.DataFrame(list(b_y_card.items()), columns=['TEAM', 'yellow_card'])
df_3 = pd.DataFrame(list(b_r_card.items()), columns=['TEAM', 'red_card'])
df_1 = pd.merge(df_1,df_2,on='TEAM')
df_de = pd.merge(df_1,df_3,on='TEAM')
df_de["season"] = count
globals()["b_f_"+str(count)] = df_de
count += 1
파울, 경고, 퇴장에 대한 코딩으로 이것도 슈팅과 마찬가지로 2000-01 시즌부터의 데이터만 있고, 그 전 데이터는 유실되어 따로 코딩을 진행하였다.
이 수치를 가지고 시각화랑 통계자료를 만들어 보았다.
이것도 공격력과 마찬가지로 통계자료를 38로 나누어 경기당의 수치로 보았다.
Mean 값을 보았을 때,
경기당 실점은 0.8골, 파울은 10.7번, 경고 1.5번, 퇴장 0.06번을 한다는 것을 알 수있다.
득점에 비하여 실점이 상당히 적은 것을 알 수있고, 경기당 10번의 파울로 생각보다 적은 값이 나온 것 같다.
( 그만큼 수비를 잘한다고 생각한다. )
[ 결론 ]
마지막 결론으로 현재 토트넘과 비교를 하기위해 위에서 했던 우승팀의 공격력과 수비력의 똑같은 컬럼으로 뽑아보았다.
토트넘은 30경기만 한 데이터를 가지고 통합하여 /30을 해주어 경기당으로 비교할 수 있게 하였다.
(파란색은 안좋은 것이고 빨간색은 좋은 것이라고 생각하면 된다.)
공격력은 예상한 대로 많이 부족하다는 것을 보여주고 있다.
수비력은 수비축구답게 큰 차이를 안보이지만, 우승팀보다는 부족한 수치이다.
경고만 더 좋은 수치를 가진 것을 보아, 역시 경고와 퇴장은 수비력과 큰 차이가 없는 것같다.
토트넘만 보기에는 저 데이터가 믿을 수 있는 수치인지 알 수 없기 때문에
현재 1등인 맨시티의 공격력과 수비력도 비교를 해보았다.
확실히 토트넘과 많이 비교된다는 것을 보여준다.
(파란색은 안좋은 것 , 빨간색은 좋은 것)
공격력은 약간 부족하지만, 아직 7경기나 남아있어서 충분히 따라잡을 수 있는 수치이다.
수비력은 우승하기 충분한 수비력이라는 것을 보여준다.
이번 데이터 분석을 통해 토트넘이 현재 얼마나 부족한 점이 많은지 알아보았다.
Kane 과 Son 의 선수 기량이 세계최고급이지만, 공격력에서도 부족한 점이 많다.
수비는 부족한 점이 한 두가지가 아니라서 말을 아끼도록 하겠다.
일단 이번 2020-21시즌은 챔스권만 진출해도 정말로 잘한 것이라고 판단된다.
(아마 못할 것 같다.)
(수정)
생각보다 보시는 분들도 많고 댓글로 코드 질문이 많아서 EPL 프로젝트 했던 코드 올렸습니다.
공개하기 부끄러울 정도로 미흡한 코드입니다... 감사합니다.
https://github.com/LEEJEHEON/2021_04_EPL_Analysis
'Project_Log' 카테고리의 다른 글
[ 빅데이터의 이해 ] 공공 데이터를 이용하여 지하철 이용객 데이터 분석 - 3 (0) | 2022.02.06 |
---|---|
[ 빅데이터의 이해 ] 공공 데이터를 이용하여 지하철 이용객 데이터 분석 - 2 (2) | 2022.02.02 |
[ 빅데이터의 이해 ] 공공 데이터를 이용하여 지하철 이용객 데이터 분석 - 1 (1) | 2022.02.02 |
[ Python Project ] EPL 데이터 분석을 통한 토트넘의 현실 - 1 (3) | 2021.04.15 |