专栏首页Python机器学习算法说书人用 Python 对成绩分类汇总

用 Python 对成绩分类汇总

这学期我们每个人需要填写三张学年鉴定表,每一张表中都有学业总平均分和考试课平均分两项内容,如果想用手工的方式算出这两项内容不知道要花多久,所以我建议编写一个算法(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,不备注可是会被拒绝的哦~!

本文分享自微信公众号 - Python机器学习算法说书人(Python-ML-Algorithm),作者:小陈学Python

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python 设计模式(4):生成器模式

    生成器模式与工厂方法模式有着相似之处,两者都属于创建型模式,并且都是将对象创建的任务交给一个单独的类去完成。

    不可言诉的深渊
  • Python设计模式(9):桥接模式

    在实际生活中,某些事物由于自身的逻辑,具有两个或多个维度的变化。例如,国家武装力量分为海军、陆军、空军三个军种,海、陆、空三军各自又有军、师、旅、团、营等建制。...

    不可言诉的深渊
  • 用通俗易懂的语言讲解 kNN

    最近有个同学问我 k-means 和 kNN 是不是差不多?其实差太多了,k-means 是在不知道类别的情况下进行分类的,而 kNN 是通过已经存在的已经分好...

    不可言诉的深渊
  • 基于tensorflow+CNN的搜狐新闻文本分类

    tensorflow是谷歌google的深度学习框架,tensor中文叫做张量,flow叫做流。 CNN是convolutional neural netwo...

    潇洒坤
  • 太实用了!自己动手写软件——我们的密码破解器终于完成了

    之前我们完成了密码破解工具的界面,今天我们终于把软件功能给实现了,我们先来看看实现效果吧

    菜鸟小白的学习分享
  • 【NLP基础】NLP关键字提取技术之LDA算法原理与实践

    人们是如何从大量文本资料中便捷得浏览和获取信息?答案你肯定会说通过关键字。仔细想想,我们人类是怎么提取关键词?我们从小就接触语言,语法,当听到或者看到一句话时,...

    zenRRan
  • 如何用Python抓取最便宜的机票信息(上)

    这个项目的目标是为一个特定的目的地建立一个web scraper,它将运行和执行具有灵活日期的航班价格搜索(在您首先选择的日期前后最多3天)。它保存一个包含结果...

    AiTechYun
  • Python函数参数(补充)

      最近看了几篇文章,介绍函数传参数的,下面一一介绍,希望对你理解Python有帮助。

    py3study
  • 基于tensorflow+CNN的垃圾邮件文本分类

    tensorflow是谷歌google的深度学习框架,tensor中文叫做张量,flow叫做流。 CNN是convolutional neural netwo...

    潇洒坤
  • SAP 性能优化之---数据查询(常见办法)

    email:lhui@hndldz.com & yuqishow@qq.com

    CINDYLI

扫码关注云+社区

领取腾讯云代金券