Bootstrap

【Python】Pandas库实验练习

编译平台:PyCharm
使用语言:Python
版本:2020.1

一、前言

  实验:现给出球员的赛场信息表 ,请分析该表,排名球员实力。
  表资源下载链接:data.xlsx

二、代码

2.1 导入库

import re
import matplotlib.pyplot as plt
import pandas  
from collections import Counter

  有关上述库的理解如下:

Python库描述
re提供字符串分割方法
matplotlib提供图像可视化
pandas提供获取Excel表等文件类型的数据手段
collections提供统计数方法

2.2 准备Excel路径

# data.xlsx路径
FilePath = "C:\\Users\\Administrator\\Desktop\\pandas入门\\data.xlsx"
OutPath = "C:\\Users\\Administrator\\Desktop\\pandas入门\\NewData.xlsx"

  如上图所示,为笔者的data.xlsx本地路径。输出路径为后续将筛除的新数据进行导出的路径。特别注意:你需要将你的本地路径覆盖上图中的路径。

2.3 提取Excel数据

  为方便理解,我们使用pandas直接引用,不做缩写命名。

List = pandas.read_excel(FilePath)

  pandas库提供read_excel()方法来读取Excel表中的数据。
  关于更多了解该函数方法,请参考CSDN作者:leenuxcore — Pandas read_excel( )参数详解

  输出的部分结果如下图所示:
部分数据图

2.4 修正格式(可忽略)

# 解决数据输出时列名不对齐的问题
pd.set_option('display.unicode.east_asian_width', True)

2.5 提取关键数据

TeamRole = pandas.DataFrame(data=List, index=None, columns=['球员', '进球(点球)', '射门', '射正', '球队'])

  出于数据类型多,我们只筛选出相对有用的列。pandas库提供DataFrame()方法允许我们从获取的数据集中,拿取指定列、行的数据集。
  关于该函数方法,请参考CSDN作者:daydayup_668819 — python下的Pandas中DataFrame基本操作(一),基本函数整理

  提取数据部分图如下图所示:
部分数据图

2.6 数据清洗阶段

2.6.1 认识射门与射正
描述
射门指用踢球、头顶球、铲球等技术将球射向对方球门。是进攻的最终目的,也是比赛胜负的关键。
射正(进攻)从进球的角度,在最后一次出球(射门)时,完成破门或对球门造成威胁。
射正(防守)从防守的角度,最后一次触球,踢向球门的中路,导致门将将球没收或将球扑出,浪费了一次进攻机会

  笔者个人理解  射门 —— 向门的方向射球
          射球 —— 射向门内区域(不包含门框)

2.6.2 正则表达式提取关键数据

  由于每名球员中,存在 进球数(点球) 这一选项,我们需要使用re库,即正则表达式对数据进行分割。部分描述图
  首先,我们通过len()获取列长度。或许也有其他更好的方法直接获取列长,命名为RoleCount(取名为"球员数量")。

RoleCount = len(TeamRole)

  其次,受限于我们从Excel中获取的数据格式有intstring两个类型混合,我们决定使用re库提供的split()方法对数据进行提取。于是,我们准备了数组GoalMainGoalPoint进行提取的数据存储。如下所示:

GoalMain = []   # 存储总进球数
GoalPoint = []  # 存储点射进球数

  但是,re库提供的split()方法在非包含指定分割字符的前提下,返回报错的问题。原因是存在int类型的数据。
  于是,为解决此问题我们引入了isdigit()方法来辨识字符串是否为数值。在此之前,我们需要将所有数据类型强转为string类型,来满足isdigit()的前提条件。

for index in range(0, RoleCount):
    value = TeamRole['进球(点球)'][index]  # 索引进球数据
    value = str(value)  # 强转str
    # 如果数据为纯数字,直接赋值,否则进行数据提取
    # 判断字符串内部是否为纯数字
    if value.isdigit():
        data = value  # 直接赋值
        GoalMain.append(data)  # 添加进球总数
        GoalPoint.append(0)  # 添加点射进球数0
    else:
        data = re.split('[()]', value)  # 提取数据
        # print(len(data))  # 获取数据大小
        # 输出数据 ['数据1', '数据2', 'null']
        GoalMain.append(data[0])  # 添加进球总数
        GoalPoint.append(data[1])  # 添加点射进球数

特别注意
  数据内容 17(2),在使用split()分割后,其分割后的数据为Array类型,即分割数据为['17', '2', ''],故获取的重要数据分为别data[0]data[1]
  数据内容 16,因为没有点球数,故计数为0。

  处理后的数据集如下所示:
提取数据图

2.6.3 添加新列

  如下所示,我们将获取到的数据分别命名为"总进球""点进球",并将数组GoalMainGoalPoint分别赋值。

TeamRole['总进球'] = GoalMain
TeamRole['点进球'] = GoalPoint
2.6.4 删除旧列

  删除'进球(点球)'列,因为我们从中提取到想要的数据集,后续将不再需要。

del TeamRole['进球(点球)']
2.6.5 提取的数据表

部分数据图

2.7 统计数据

  由 2.6.1 认识射门与射正 提供的了解,新的数据计算如下所示:

算式描述
框内命中率= 射正 / 射门射进球框内区域方向的概率
进球率= 进球 / 射正在射进球框内区域方向上的进球得分概率

  于是,准备两个数组EntryRateGoalRate作为存储数据组:

EntryRate = []  # 进门率
GoalRate = []  # 进球率

  接着,遍历各列,获取数据,计算。将计算的结果添加至数据组中。其中round()方法帮助我们控制数据的小数点后位数,以更直观的美化数据观感,如下图示:

for index in range(0, RoleCount):
    value_SP = float(TeamRole['射正'][index])
    value_SM = float(TeamRole['射门'][index])
    value_go = float(TeamRole['总进球'][index])
    # 射正/射门 = 框内命中率
    valueA = value_SP / value_SM
    # 进球/射正 = 进球率
    valueB = value_go / value_SP
    # 添加
    EntryRate.append(round(valueA, 3))
    GoalRate.append(round(valueB, 3))

  特别注意:出于获取的内容为字符串string类型,需要float()强转数据类型,后续计算准备。

  重复 2.6.3 添加新列 操作,将新数据组添加至TeamRole中,如下图所示:

TeamRole['进门率'] = EntryRate
TeamRole['进球率'] = GoalRate

2.8 制图阶段

2.8.0 最终效果图展示

在这里插入图片描述

2.8.1 准备数据

  如 2.8.0 最终效果图展示所示,x轴为球员,y+为进门率,y-为进球率。并附有两条平均水平线作参考。

  分别获取TeamRole['球员']TeamRole['进球率']TeamRole['进门率']

x1 = TeamRole['球员']
y2 = TeamRole['进球率']
y3 = TeamRole['进门率']

  由于笔者在Python中尚未找到average()方法,可能有但就是完美的错过了。选择使用sum()计算各数据列总和,来求均值。得到的均值为 各率参考线

ave_Entry = sum(y2)/RoleCount
ave_Goal = sum(y3)/RoleCount
2.8.2 绘制关系图
plt.figure(figsize=(13, 8))
plt.bar(x1, y2, width=0.4, label='进球率')
plt.xticks(rotation=45)
plt.bar(x1, -y3, width=0.4, label='进门率')
2.8.3 绘制参考线
plt.axhline(y=ave_Entry, ls=":", c="red", label='平均进门率')  # 添加水平直线
plt.axhline(y=-ave_Goal, ls=":", c="blue", label='平均进球率')  # 添加水平直线
2.8.4 预防图像数据乱码

  出于编码格式的缘由,一部分中文字体无法正常显示(即 乱码)。需要使用以下两行代码对输出文字格式进行修正。

plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
2.8.5 其他数据内容补充

  为X轴、Y轴添加标签说明,如下所示:

plt.xlabel('球员')
plt.ylabel('百分比 %')

  将标签内容以微型图方式呈现于数据图右上方,如下所示:

plt.legend()

  命名数据的标题内容,并呈现于数据图正上方。

plt.title('球员进球率(条形图)')
2.8.6 显示图
plt.show()

2.9 输出Excel表

  result为我们在 2.7 统计数据 完成后获取的最终数据。OutPath为我们在 2.2 准备Excel路径 时已经完成。

result.to_excel(OutPath, sheet_name='NewData')

三、后记

  如有错误,请评论指正,或联系作者进行更正。

;