Python是一种通用的编程语言,适用于各种开发任务,包括机器学习、数据科学和数据分析等复杂任务。Python不仅易于学习,还拥有众多出色的库,使其成为许多人的首选编程语言。本文将展示Python的一个用例,即分析印度板球运动员MS Dhoni在一日国际赛(ODI)职业生涯的表现。
如果熟悉网络爬虫的概念,可以从ESPN Cricinfo链接抓取数据。如果不了解网络爬虫,也不用担心!可以直接从这里下载数据。数据以Excel文件的形式提供下载。一旦有了数据集,需要将其加载到Python中。可以使用以下代码将数据集加载到Python中:
import pandas as pd
import numpy as np
import datetime
import matplotlib.pyplot as plt
import seaborn as sns
# 读取数据集
df = pd.read_excel('MS_Dhoni_ODI_record.xlsx')
print(df.head())
如果数据正确加载,可以进行下一步,数据清洗和准备。
这些数据来自网页,因此不是很干净。将首先删除对手字符串中的前两个字符,因为它们不需要。
# 删除对手字符串中的前两个字符
df['opposition'] = df['opposition'].apply(lambda x: x[2:])
接下来,将创建一个列,表示比赛进行的年份。请确保DataFrame中的日期列以DateTime格式存在。如果不是,请使用pd.to_datetime()将其转换为DateTime格式。
# 创建比赛年份的特征
df['year'] = df['date'].dt.year.astype(int)
还将创建一个列,表示Dhoni在那局比赛中是否未出局。
# 创建未出局的特征
df['score'] = df['score'].apply(str)
df['not_out'] = np.where(df['score'].str.endswith('*'), 1, 0)
现在将删除ODI编号列,因为它对分析没有价值。
# 删除无价值的ODI编号特征
df.drop(columns='odi_number', inplace=True)
还将从记录中删除Dhoni没有击球的那些局,并在新的DataFrame中存储这些信息。
# 删除Dhoni未击球的局并存储在新的DataFrame中
df_new = df.loc[((df['score'] != 'DNB') & (df['score'] != 'TDNB')), 'runs_scored':]
最后,将修复新DataFrame中所有列的数据类型。
# 修复数值列的数据类型
df_new['runs_scored'] = df_new['runs_scored'].astype(int)
df_new['balls_faced'] = df_new['balls_faced'].astype(int)
df_new['strike_rate'] = df_new['strike_rate'].astype(float)
df_new['fours'] = df_new['fours'].astype(int)
df_new['sixes'] = df_new['sixes'].astype(int)
将查看MS Dhoni ODI职业生涯的描述性统计。可以使用以下代码进行此操作:
first_match_date = df['date'].dt.date.min().strftime('%B %d, %Y') # 第一场比赛
print('第一场比赛:', first_match_date)
last_match_date = df['date'].dt.date.max().strftime('%B %d, %Y') # 最后一场比赛
print('最后一场比赛:', last_match_date)
number_of_matches = df.shape[0] # 职业生涯中比赛场数
print('职业生涯中比赛场数:', number_of_matches)
number_of_inns = df_new.shape[0] # 职业生涯中局数
print('职业生涯中局数:', number_of_inns)
not_outs = df_new['not_out'].sum() # 职业生涯中未出局次数
print('职业生涯中未出局次数:', not_outs)
runs_scored = df_new['runs_scored'].sum() # 职业生涯中得分
print('职业生涯中得分:', runs_scored)
balls_faced = df_new['balls_faced'].sum() # 职业生涯中面对的球数
print('职业生涯中面对的球数:', balls_faced)
career_sr = (runs_scored / balls_faced)*100 # 职业生涯击球率
print('职业生涯击球率: {:.2f}'.format(career_sr))
career_avg = (runs_scored / (number_of_inns - not_outs)) # 职业生涯平均分
print('职业生涯平均分: {:.2f}'.format(career_avg))
highest_score_date = df_new.loc[df_new.runs_scored == df_new.runs_scored.max(), 'date'].values[0]
highest_score = df.loc[df.date == highest_score_date, 'score'].values[0] # 职业生涯最高分
print('职业生涯最高分:', highest_score)
hundreds = df_new.loc[df_new['runs_scored'] >= 100].shape[0] # 职业生涯中百分次数
print('职业生涯中百分次数:', hundreds)
fifties = df_new.loc[(df_new['runs_scored']>=50)&(df_new['runs_scored']<100)].shape[0] # 职业生涯中五十分数
print('职业生涯中五十分数:', fifties)
fours = df_new['fours'].sum() # 职业生涯中四分次数
print('职业生涯中四分次数:', fours)
sixes = df_new['sixes'].sum() # 职业生涯中六分次数
print('职业生涯中六分次数:', sixes)
输出结果如下:
这为提供了MS Dhoni职业生涯的总体概览。他从2004年开始比赛,最后一次参加ODI是在2019年。在超过15年的职业生涯中,他共得了10个百分和惊人的73个五十。他的职业生涯得分超过10,000分,平均得分为50.6,击球率为87.6。他职业生涯中的最高得分是183*。
首先,将看看他对抗不同对手的比赛场数。可以使用以下代码片段来实现这一目的:
# 不同对手的比赛场数
df['opposition'].value_counts().plot(kind='bar', title='不同对手的比赛场数', figsize=(8, 5));
输出结果如下:
可以看到,他对抗斯里兰卡、澳大利亚、英格兰、西印度群岛、南非和巴基斯坦的比赛最多。
让看看他对抗不同对手的得分。可以使用以下代码片段来生成结果:
runs_scored_by_opposition = pd.DataFrame(df_new.groupby('opposition')['runs_scored'].sum())
runs_scored_by_opposition.plot(kind='bar', title='不同对手的得分', figsize=(8, 5))
plt.xlabel(None);
输出结果如下:
可以看到,Dhoni在对抗斯里兰卡的比赛中得分最多,其次是澳大利亚、英格兰和巴基斯坦。他对抗这些队伍的比赛也很多,所以这是有道理的。
为了更清晰地了解,让看看他对抗每个队伍的击球平均分。以下代码将帮助获得所需的结果:
innings_by_opposition = pd.DataFrame(df_new.groupby('opposition')['date'].count())
not_outs_by_opposition = pd.DataFrame(df_new.groupby('opposition')['not_out'].sum())
temp = runs_scored_by_opposition.merge(innings_by_opposition, left_index=True, right_index=True)
average_by_opposition = temp.merge(not_outs_by_opposition, left_index=True, right_index=True)
average_by_opposition.rename(columns = {'date': 'innings'}, inplace=True)
average_by_opposition['eff_num_of_inns'] = average_by_opposition['innings'] - average_by_opposition['not_out']
average_by_opposition['average'] = average_by_opposition['runs_scored'] / average_by_opposition['eff_num_of_inns']
average_by_opposition.replace(np.inf, np.nan, inplace=True)
major_nations = ['Australia', 'England', 'New Zealand', 'Pakistan', 'South Africa', 'Sri Lanka', 'West Indies']
For generating the plot, use the code snippet below:
plt.figure(figsize = (8, 5))
plt.plot(average_by_opposition.loc[major_nations, 'average'].values, marker='o')
plt.plot([career_avg]*len(major_nations), '--')
plt.title('对抗主要队伍的平均分')
plt.xticks(range(0, 7), major_nations)
plt.ylim(20, 70)
plt.legend(['对抗对手的平均分', '职业生涯平均分']);
输出结果如下:
可以看到,Dhoni在对抗澳大利亚、英格兰和斯里兰卡等强队时表现非常出色。他的对抗这些队伍的平均分要么接近他的职业生涯平均分,要么略高。唯一一个他表现不佳的队伍是南非。
现在让看看他每年的统计数据。将从他首次亮相后每年参加的比赛场数开始。代码如下:
df['year'].value_counts().sort_index().plot(kind='bar', title='每年参加的比赛场数', figsize=(8, 5))
plt.xticks(rotation=0);
图表如下:
可以看到,在2012年、2014年和2016年,Dhoni为印度参加的ODI比赛非常少。总体而言,在2005-2009年之后,他参加的比赛平均数量略有减少。
还应该看看他每年得分的情况。代码如下:
df_new.groupby('year')['runs_scored'].sum().plot(kind='line', marker='o', title='每年得分', figsize=(8, 5))
years = df['year'].unique().tolist()
plt.xticks(years)
plt.xlabel(None);
输出结果如下:
可以清楚地看到,Dhoni在2009年得分最多,其次是2007年和2008年。2010年后,他的得分开始减少(因为参加的比赛数量也开始减少)。
最后,让看看他职业生涯的击球平均分进展。这是一个时间序列数据,并在折线图上绘制。代码如下:
df_new.reset_index(drop=True, inplace=True)
career_average = pd.DataFrame()
career_average['runs_scored_in_career'] = df_new['runs_scored'].cumsum()
career_average['innings'] = df_new.index.tolist()
career_average['innings'] = career_average['innings'].apply(lambda x: x+1)
career_average['not_outs_in_career'] = df_new['not_out'].cumsum()
career_average['eff_num_of_inns'] = career_average['innings'] - career_average['not_outs_in_career']
career_average['average'] = career_average['runs_scored_in_career'] / career_average['eff_num_of_inns']
The code snippet for the plot will be:
plt.figure(figsize = (8, 5))
plt.plot(career_average['average'])
plt.plot([career_avg]*career_average.shape[0], '--')
plt.title('职业生涯平均分进展')
plt.xlabel('局数')
plt.legend(['平均分进展', '职业生涯平均分']);