前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用 Python 对成绩分类汇总

用 Python 对成绩分类汇总

作者头像
不可言诉的深渊
发布2019-10-08 16:03:32
1K0
发布2019-10-08 16:03:32
举报

这学期我们每个人需要填写三张学年鉴定表,每一张表中都有学业总平均分和考试课平均分两项内容,如果想用手工的方式算出这两项内容不知道要花多久,所以我建议编写一个算法(Excel 的函数啥的本质上也是算法)计算这两项内容,下面我就以我的成绩为例讲一下用 Python 算出这两项内容的步骤。

概述

我们打开学校的教务系统,如图所示。

点击成绩查询,如图所示。

随后选择某一学年,然后点击按学年查询,如图所示。

我们可以发现这里只有成绩,没有考核方式,而且里面有非法数据,比如所谓的“合格”。我们暂时先不处理这些非法数据,先找到考核方式在哪里,如图所示。

点击培养计划,如图所示。

这样就可以看到考核方式了,然后把建议修读学期改成全部,其他不变,如图所示。

可以发现它默认是分页显示,每页显示 10 条数据,然而我们需要一页显示所有数据。我这边总共 59 条数据,每页显示 10 条数据,那么我们直接把每页显示的数据条数改成大于等于 59 不就可以了吗?在这里我改成 60,如图所示。

既然数据找到了,那么算法实现起来就简单了,根据课程代码(如果课程名称唯一,也可以根据课程名称,我是根据课程名称进行合并的)把每一学年的成绩和考核方式合并到一张表中。

新建项目

我们用 PyCharm 新建一个 Scientific 项目,项目名称和目录随便(因为是对成绩进行分类汇总,所以我就把项目叫做 GradeSummary),如图所示。

点击 CREATE,等待片刻后如图所示。

接下来在 data 目录里面新建两个 Excel 文件,名称如图所示。

然后打开名为成绩统计.xlsx,在里面创建三个 sheet,如图所示。

接着去教务系统成绩查询页,把第一学年的成绩数据放到第一个 sheet,第二学年的放到第二个 sheet,第三学年的放到第三个 sheet,如图所示。

如果和上图的格式差不多就可以保存关闭,打开考核方式统计.xlsx,去教务系统把考核方式数据复制到这个 workbook 的第一张工作表中,如图所示。

如果格式和上图格式差不多就可以保存关闭了。

算法实现

算法的实现过程比较简单,分为以下几步:载入成绩,载入考核方式,合并,处理,计算总平均分,计算考试科平均分。(过程的顺序不唯一,比如载入成绩和载入考核方式可以互换)。

下面就可以搭建一个框架了,代码如下:

class GradeSummary:
    def __init__(self):
        pass

    def load_grade(self):
        pass

    def load_assessment_method(self):
        pass

    def merge(self):
        pass

    def process(self):
        pass

    def calculate_all_average(self):
        pass

    def calculate_examination_average(self):
        pass


if __name__ == '__main__':
    grade_summary = GradeSummary()
    grade_summary.load_grade()
    grade_summary.load_assessment_method()
    grade_summary.merge()
    grade_summary.process()
    grade_summary.calculate_all_average()
    grade_summary.calculate_examination_average()

01

初始化

在其中我们需要三个数据集列表,一个是存放成绩数据,一个是存放考核方式数据,还有一个是存放合并后的数据。每个列表中有三个元素(第几个元素就对应第几学年)。另外我们还需要一个学年的序列,因为要算每一学年的学业总平均分和考试课平均分。知道这些写出构造方法就是轻而易举了,代码如下:

    def __init__(self):
        self.dataset_list1 = [{'课程名称': [], '成绩': []}, {'课程名称': [], '成绩': []}, {'课程名称': [], '成绩': []}]
        self.dataset_list2 = [{'课程名称': [], '考核方式': []}, {'课程名称': [], '考核方式': []},
                              {'课程名称': [], '考核方式': []}]
        self.dataset_list = [{'课程名称': [], '成绩': [], '考核方式': []}, {'课程名称': [], '成绩': [], '考核方式': []},
                             {'课程名称': [], '成绩': [], '考核方式': []}]
        self.school_years = '2016-2017', '2017-2018', '2018-2019'

02

载入成绩

载入成绩的实现很简单,读取成绩统计.xlsx,顺序遍历三个 sheet,在第一次遍历过程中把课程名称的数据放到 self.dataset_list1[0]['课程名称']里面,第二次遍历过程中把课程名称的数据放到 self.dataset_list1[1]['课程名称']里面,以此类推。

在每次遍历的过程中仅仅载入一个课程名称有点说不过去,我们还需要把成绩载入一下,成绩就是考试成绩,补考成绩,重修成绩三个中取最大值。在这里要处理的问题有点多,下面我们来一一解决一下。

第一个问题,如果成绩,补考成绩,重修成绩对应的数据类型不一样,比如我,没有补考和重修,补考成绩和重修成绩对应的数据类型是字符串,怎么办?这个问题解决起来很简单,只要把补考成绩和重修成绩修改成 0 就行了,这样就可以进行比较,而且结果没有错误。

第二个问题,像“合格”这样的数据怎么办?最终我们是选择忽略掉这种数据,但是我们现在不忽略,直接令成绩为空字符串。

知道了这些代码实现就简单了,代码如下:

    def load_grade(self):
        workbook = open_workbook('data/成绩统计.xlsx')
        for i in range(3):
            sheet = workbook.sheet_by_index(i)
            headers = [header.value for header in sheet.row(0)]
            self.dataset_list1[i]['课程名称'] = sheet.col_values(headers.index('课程名称'), 1)
            grade_list = [[], [], []]
            grade_list[0] = sheet.col_values(headers.index('成绩'), 1)
            grade_list[1] = sheet.col_values(headers.index('补考成绩'), 1)
            grade_list[2] = sheet.col_values(headers.index('重修成绩'), 1)
            for j in range(len(grade_list[0])):
                if isinstance(grade_list[0][j], float):
                    if not isinstance(grade_list[1][j], float):
                        grade_list[1][j] = 0.0
                    if not isinstance(grade_list[2][j], float):
                        grade_list[2][j] = 0.0
            for j in range(len(grade_list[0])):
                if isinstance(grade_list[0][j], float):
                    self.dataset_list1[i]['成绩'].append(max(grade_list[0][j], grade_list[1][j], grade_list[2][j]))
                else:
                    self.dataset_list1[i]['成绩'].append('')

03

载入考核方式

载入考核方式的实现很简单,读取考核方式统计.xlsx,获取课程名称,考核方式,建议修读学期这三条数据,然后根据建议修读学期计算对应的学年,最后根据学年计算出索引,下面我就讲一下如何计算。

如果建议修读学期是 1 或者 2,那么对应第 1 学年;如果建议修读学期是 3 或者 4,那么对应第 2 学年;以此类推。我们可以发现:(建议修读学期[i]-1)//2+1 就是第几学年,所以索引 = (建议修读学期[i]-1)//2+1-1 = (建议修读学期[i]-1)//2。因为我总共只有 3 个学年,所以索引必须小于等于 2!

最后把数据存放到对应的容器中就行了,代码如下:

    def load_assessment_method(self):
        dataset = {'课程名称': [], '考核方式': [], '建议修读学期': []}
        workbook = open_workbook('data/考核方式统计.xlsx')
        sheet = workbook.sheet_by_index(0)
        headers = [header.value for header in sheet.row(0)]
        dataset['课程名称'] = sheet.col_values(headers.index('课程名称'), 1)
        dataset['考核方式'] = sheet.col_values(headers.index('考核方式'), 1)
        dataset['建议修读学期'] = sheet.col_values(headers.index('建议修读学期'), 1)
        for i in range(len(dataset['课程名称'])):
            index = (int(dataset['建议修读学期'][i])-1)//2
            if index <= 2:
                self.dataset_list2[index]['课程名称'].append(dataset['课程名称'][i])
                self.dataset_list2[index]['考核方式'].append(dataset['考核方式'][i])

04

合并

合并的实现很简单,把成绩数据集列表(self.dataset_list1)中第 i 个数据集和考核方式数据集列表(self.dataset_list2)中第 i 个数据集按照课程名称合并到 self.dataset_list[i] 中,其中 0 <= i <= 2。合并完成之后删除成绩数据集列表和考核方式数据集列表,代码如下:

    def merge(self):
        for i in range(3):
            for j in range(len(self.dataset_list1[i]['课程名称'])):
                for k in range(len(self.dataset_list2[i]['课程名称'])):
                    if self.dataset_list1[i]['课程名称'][j] == self.dataset_list2[i]['课程名称'][k]:
                        self.dataset_list[i]['课程名称'].append(self.dataset_list1[i]['课程名称'][j])
                        self.dataset_list[i]['成绩'].append(self.dataset_list1[i]['成绩'][j])
                        self.dataset_list[i]['考核方式'].append(self.dataset_list2[i]['考核方式'][k])
                        del self.dataset_list2[i]['课程名称'][k]
                        del self.dataset_list2[i]['考核方式'][k]
                        break
        del self.dataset_list1
        del self.dataset_list2

05

处理

处理的实现很简单,如果成绩是数,保留该数据。在这里我使用一个临时的数据集列表保留筛选后的数据,最后把临时的数据集列表赋值给 self.dataset_list,代码如下:

    def process(self):
        dataset_list = [{'课程名称': [], '成绩': [], '考核方式': []}, {'课程名称': [], '成绩': [], '考核方式': []},
                        {'课程名称': [], '成绩': [], '考核方式': []}]
        for i in range(3):
            for j in range(len(self.dataset_list[i]['课程名称'])):
                if isinstance(self.dataset_list[i]['成绩'][j], float):
                    dataset_list[i]['课程名称'].append(self.dataset_list[i]['课程名称'][j])
                    dataset_list[i]['成绩'].append(self.dataset_list[i]['成绩'][j])
                    dataset_list[i]['考核方式'].append(self.dataset_list[i]['考核方式'][j])
        self.dataset_list = dataset_list

06

计算总平均分

计算总平均分很简单,课程成绩总和除以课程数目,不要忘了一学年一学年的计算,代码如下:

    def calculate_all_average(self):
        print('学业总平均分')
        for i in range(3):
            print(self.school_years[i], sum(self.dataset_list[i]['成绩'])/len(self.dataset_list[i]['成绩']))

07

计算考试科平均分

最后是计算考试课平均分,也就是在学业总平均分的基础上多了一步筛选操作——筛选出考试课,代码如下:

    def calculate_examination_average(self):
        print('考试科平均分')
        for i in range(3):
            examination_grade_list = []
            for j in range(len(self.dataset_list[i]['课程名称'])):
                if self.dataset_list[i]['考核方式'][j] == '考试':
                    examination_grade_list.append(self.dataset_list[i]['成绩'][j])
            print(self.school_years[i], sum(examination_grade_list)/len(examination_grade_list))

最后我直接给出完整代码:

from xlrd import open_workbook
from time import time


class GradeSummary:
    def __init__(self):
        self.dataset_list1 = [{'课程名称': [], '成绩': []}, {'课程名称': [], '成绩': []}, {'课程名称': [], '成绩': []}]
        self.dataset_list2 = [{'课程名称': [], '考核方式': []}, {'课程名称': [], '考核方式': []},
                              {'课程名称': [], '考核方式': []}]
        self.dataset_list = [{'课程名称': [], '成绩': [], '考核方式': []}, {'课程名称': [], '成绩': [], '考核方式': []},
                             {'课程名称': [], '成绩': [], '考核方式': []}]
        self.school_years = '2016-2017', '2017-2018', '2018-2019'

    def load_grade(self):
        workbook = open_workbook('data/成绩统计.xlsx')
        for i in range(3):
            sheet = workbook.sheet_by_index(i)
            headers = [header.value for header in sheet.row(0)]
            self.dataset_list1[i]['课程名称'] = sheet.col_values(headers.index('课程名称'), 1)
            grade_list = [[], [], []]
            grade_list[0] = sheet.col_values(headers.index('成绩'), 1)
            grade_list[1] = sheet.col_values(headers.index('补考成绩'), 1)
            grade_list[2] = sheet.col_values(headers.index('重修成绩'), 1)
            for j in range(len(grade_list[0])):
                if isinstance(grade_list[0][j], float):
                    if not isinstance(grade_list[1][j], float):
                        grade_list[1][j] = 0.0
                    if not isinstance(grade_list[2][j], float):
                        grade_list[2][j] = 0.0
            for j in range(len(grade_list[0])):
                if isinstance(grade_list[0][j], float):
                    self.dataset_list1[i]['成绩'].append(max(grade_list[0][j], grade_list[1][j], grade_list[2][j]))
                else:
                    self.dataset_list1[i]['成绩'].append('')

    def load_assessment_method(self):
        dataset = {'课程名称': [], '考核方式': [], '建议修读学期': []}
        workbook = open_workbook('data/考核方式统计.xlsx')
        sheet = workbook.sheet_by_index(0)
        headers = [header.value for header in sheet.row(0)]
        dataset['课程名称'] = sheet.col_values(headers.index('课程名称'), 1)
        dataset['考核方式'] = sheet.col_values(headers.index('考核方式'), 1)
        dataset['建议修读学期'] = sheet.col_values(headers.index('建议修读学期'), 1)
        for i in range(len(dataset['课程名称'])):
            index = (int(dataset['建议修读学期'][i])-1)//2
            if index <= 2:
                self.dataset_list2[index]['课程名称'].append(dataset['课程名称'][i])
                self.dataset_list2[index]['考核方式'].append(dataset['考核方式'][i])

    def merge(self):
        for i in range(3):
            for j in range(len(self.dataset_list1[i]['课程名称'])):
                for k in range(len(self.dataset_list2[i]['课程名称'])):
                    if self.dataset_list1[i]['课程名称'][j] == self.dataset_list2[i]['课程名称'][k]:
                        self.dataset_list[i]['课程名称'].append(self.dataset_list1[i]['课程名称'][j])
                        self.dataset_list[i]['成绩'].append(self.dataset_list1[i]['成绩'][j])
                        self.dataset_list[i]['考核方式'].append(self.dataset_list2[i]['考核方式'][k])
                        del self.dataset_list2[i]['课程名称'][k]
                        del self.dataset_list2[i]['考核方式'][k]
                        break
        del self.dataset_list1
        del self.dataset_list2

    def process(self):
        dataset_list = [{'课程名称': [], '成绩': [], '考核方式': []}, {'课程名称': [], '成绩': [], '考核方式': []},
                        {'课程名称': [], '成绩': [], '考核方式': []}]
        for i in range(3):
            for j in range(len(self.dataset_list[i]['课程名称'])):
                if isinstance(self.dataset_list[i]['成绩'][j], float):
                    dataset_list[i]['课程名称'].append(self.dataset_list[i]['课程名称'][j])
                    dataset_list[i]['成绩'].append(self.dataset_list[i]['成绩'][j])
                    dataset_list[i]['考核方式'].append(self.dataset_list[i]['考核方式'][j])
        self.dataset_list = dataset_list

    def calculate_all_average(self):
        print('学业总平均分')
        for i in range(3):
            print(self.school_years[i], sum(self.dataset_list[i]['成绩'])/len(self.dataset_list[i]['成绩']))

    def calculate_examination_average(self):
        print('考试科平均分')
        for i in range(3):
            examination_grade_list = []
            for j in range(len(self.dataset_list[i]['课程名称'])):
                if self.dataset_list[i]['考核方式'][j] == '考试':
                    examination_grade_list.append(self.dataset_list[i]['成绩'][j])
            print(self.school_years[i], sum(examination_grade_list)/len(examination_grade_list))


if __name__ == '__main__':
    start = time()
    grade_summary = GradeSummary()
    grade_summary.load_grade()
    grade_summary.load_assessment_method()
    grade_summary.merge()
    grade_summary.process()
    grade_summary.calculate_all_average()
    grade_summary.calculate_examination_average()
    print('处理时间', time()-start)

运行结果如图所示。

今天的文章有不懂的可以后台回复“加群”,备注:小陈学Python,不备注可是会被拒绝的哦~!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python机器学习算法说书人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档