百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Python其实很简单 第二十三章 全校学生成绩统计的完整实例

csdh11 2025-03-04 11:40 9 浏览

下面是用DataFrame改写第十七章介绍的程序(p23-1.py):

from warnings import simplefilter

simplefilter(action='ignore', category=FutureWarning)

# simplefilter用于忽略第三方警告

import numpy as np

import pandas as pd

from pandas import read_excel


file='d:/student.xlsx'

#Excel文件地址,student.xlsx内容详见表18-1

df=read_excel(file,sheet_name=0,converters={'学号':str})

#将Excel文件读入DataFrame数据框架df中

df['年级']=df['学号'].str.slice(0,2)

#用slice()函数实现切片并赋值给'年级'字段

df['班级']=df['学号'].str.slice(0,4)

#用slice()函数实现切片并赋值给'班级'字段

df.总分=df.语文+df.数学+df.英语

#列求和,列赋值

df['名次']=df['总分'].rank(method='min',ascending=False)

#rank()函数当method='min'时与Excel中完全相同,ascending=False为升序排序

df.to_excel('d:/test1.xlsx',sheet_name='Sheet1',index=False)

#将DataFrame数据框架df中的数据保存到Excel文件中

#至此,完成了新建Excel文件中Sheet1工作表数据的填充工作。


dfpj=df.groupby('班级')['语文','数学','英语','总分'].mean()

#依据'班级'列进行分组,求语文、数学、英语、总分的平均值,保存到数据框架dfpj中

dfrs=df.groupby('班级')['学号'].agg({'人数':np.size})

#依据'班级'列进行分组,对'学号'列计数,并以'人数'为别名保存到数据框架df人数中

jg72=72

#设置以72分为及格分数线,用于语文、数学科目

jg60=60

#设置以60分为及格分数线,用于英语科目

yx96=96

#设置以96分为优秀分数线,用于语文、数学科目

yx80=80

#设置以96分为优秀分数线,用于英语科目

df['语及']=df['语文']

#增加新的列'语及',并将'语文'列的值对应赋给

df['数及']=df['数学']

#增加新的列'数及',并将'数学'列的值对应赋给

df['英及']=df['英语']

#增加新的列'英及',并将'英语'列的值对应赋给

df['语优']=df['语文']

#增加新的列'语优',并将'语文'列的值对应赋给

df['数优']=df['数学']

#增加新的列'数优',并将'数学'列的值对应赋给

df['英优']=df['英语']

#增加新的列'英优',并将'英语'列的值对应赋给

#以上六列目前都为成绩值,后续将用来单科及格率和优秀率

#函数fun(x,y)用于判断x>=y是否成立,成立返回1;不成交返回0

def fun(x,y):

if x>=y:

return 1

else:

return 0


df['语及']=df['语及'].apply(lambda x:fun(x,jg72))

#前面已经给'语及'赋值为'语文'的值,此语句相当于判断语文>=72是否成立

#若成立则'语及'赋值为1,否则赋值为0

df['数及']=df['数及'].apply(lambda x:fun(x,jg72))

#同上,判断数学成绩是否及格

df['英及']=df['英及'].apply(lambda x:fun(x,jg60))

#同上,判断英语成绩是否及格

df['语优']=df['语优'].apply(lambda x:fun(x,yx96))

#同上,判断语文成绩是否优秀

df['数优']=df['数优'].apply(lambda x:fun(x,yx96))

#同上,判断数学成绩是否优秀

df['英优']=df['英优'].apply(lambda x:fun(x,yx80))

#同上,判断英语成绩是否优秀

df['合格']=df['语及']+df['数及']+df['英及']

#'语及'、'数及'、'英及'的值均为0或1,故'合格'的值在0~3之间

df['优秀']=df['语优']+df['数优']+df['英优']

#'语优'、'数优'、'英优'的值均为0或1,故'优秀'的值在0~3之间

df['合格']=df['合格'].apply(lambda x:fun(x,3))

#若'合格'的值>=3(其实不可能大于),给'合格'赋值为1;否则赋值为0

df['优秀']=df['优秀'].apply(lambda x:fun(x,3))

#若'优秀'的值>=3(其实不可能大于),给'优秀'赋值为1;否则赋值为0

dfjgyx=df.groupby('班级')['语及','语优','数及','数优','英及','英优','合格','优秀'].sum()

#按照'班级'分组统计'语及'等项的和,实际上就是各个单科和三科合格、优秀的人数

dftj=pd.merge(dfpj,dfjgyx,on='班级')

#将dfpj(包含有平均分)和dfjgyx(及格、优秀人数)按照'班级'关键字连接,保存到dftj

dftj=pd.merge(dftj,dfrs,on='班级')

#将dfrs连接到dftj

dftj['语文']=round(dftj['语文'],2)

#班级语文平均分保留两位小数

dftj['数学']=round(dftj['数学'],2)

#班级数学平均分保留两位小数

dftj['英语']=round(dftj['英语'],2)

#班级英语平均分保留两位小数

dftj['总分']=round(dftj['总分'],2)

#班级每个学生的三科总分的平均值保留两位小数

dftj['语及']=round((dftj['语及']/dftj['人数'])*100,2)

#语文及格人数/班级人数*100,保留两位小数,即为语文及格率,保存到'语及'列

dftj['语优']=round((dftj['语优']/dftj['人数'])*100,2)

#语文优秀人数/班级人数*100,保留两位小数,即为语文优秀率,保存到'语优'列

dftj['数及']=round((dftj['数及']/dftj['人数'])*100,2)

#数学及格人数/班级人数*100,保留两位小数,即为数学及格率,保存到'数及'列

dftj['数优']=round((dftj['数优']/dftj['人数'])*100,2)

#数学优秀人数/班级人数*100,保留两位小数,即为数学优秀率,保存到'数优'列

dftj['英及']=round((dftj['英及']/dftj['人数'])*100,2)

#英语及格人数/班级人数*100,保留两位小数,即为英语及格率,保存到'英及'列

dftj['英优']=round((dftj['英优']/dftj['人数'])*100,2)

#英语优秀人数/班级人数*100,保留两位小数,即为英语优秀率,保存到'英优'列

dftj['合格']=round((dftj['合格']/dftj['人数'])*100,2)

#三科合格人数/班级人数*100,保留两位小数,即为三科合格率,保存到'合格'列

dftj['优秀']=round((dftj['优秀']/dftj['人数'])*100,2)

#三科优秀人数/班级人数*100,保留两位小数,即为三科优秀率,保存到'优秀'列

dftj=dftj[['人数','语文','语及','语优','数学','数及','数优','英语','英及','英优','总分','合格','优秀']]

#重新调整dftj的各个字段的次序,为输出到Excel做准备

dftj.to_excel('d:/test2.xlsx',sheet_name='Sheet1',index=True)

#将数据框架dftj的数据保存到Excel文件中,索引列'班级'也一并写入


P23-1运行后生成如下两个表格:

解决写入Excel文件的内容不被覆盖的方法

在上面的代码中,to_excel()方法将DataFrame中的数据写入了某个指定的Excel文件的指定工作表中,第二次运行程序时会将Excel中以前保存的内容覆盖掉,若要想写入到新的工作表中,可在程序中添加如下代码,它利用了openpyxl的特点,它会自动新建一个以sheet_name为名后缀序号的新工作表:

# p23-2.py:

import openpyxl

#导入openpyxl模块

#以下为自定义函数add_sheet()

def add_sheet(data, excel_writer, sheet_name):

book = openpyxl.load_workbook(excel_writer.path)

#为openyxl方法指定要打开的Excel文件地址

excel_writer.book = book

#为excel_writer方法指定工作簿

data.to_excel(excel_writer=excel_writer, sheet_name=sheet_name, index=True, header=True)

#将data数据框中的数据写入Excel文件,index为真表示添加索引列,header为真表示添加标题行

excel_writer.close()

excel_writer = pd.ExcelWriter(r"d:\test.xlsx", engine='openpyxl')

#指明用openpyxl操作Excel文件

add_sheet(dftj, excel_writer, 'bjtj')

这样,就可以在test.xlsx文件中每次都新建一个名为“bjtj+n”的工作表,而不覆盖原有的工作表。

在前述的p23-1.py中,为了获取三科成绩全部及格的人数,使用了一个自定义函数fun(x,y),用该函数先判断每一科成绩是否及格,若及格则写入一个标识值为1,若不及格则写入一个标识值为0,然后再用fun(x,y)这个函数判断三科是否全部及格。这个方法显得比较繁琐,下面给出了另一种解决方法,它通过条件筛选出三科全部及格的学生并添加到一个新的数据框架中。如下代码p22-3.py只实现了p23-1.py中的部分功能,没有计算单科及格率、优秀率等。

Py23-3.py代码:

from warnings import simplefilter

simplefilter(action='ignore', category=FutureWarning)

import numpy as np

import pandas as pd

from pandas import read_excel #导入read_execel


file='d:/student.xlsx'

df=read_excel(file,sheet_name=0,converters={'学号':str})

df['年级']=df['学号'].str.slice(0,2)

df['班级']=df['学号'].str.slice(0,4)

df.总分=df.语文+df.数学+df.英语

dfhg=df[(df['语文']>=72) & (df['数学']>=72) & (df['英语']>=60)]

#将df中符合合格标准(三科都及格)的记录保存到dfhg中

dfyx=df[(df['语文']>=96) & (df['数学']>=96) & (df['英语']>=80)]

#将df中符合优秀标准(三科都优秀)的记录保存到dfhg中

dfpj=df.groupby('班级')['语文','数学','英语','总分'].mean()

#求班级单科平均值和总分平均值保存到dfpj中

dfrs=df.groupby('班级')['学号'].agg({'人数':np.size})

#dfrs中保存各班总人数

dfhg=dfhg.groupby('班级')['学号'].agg({'合格':np.size})

#dfhg中保存各班合格人数

dfyx=dfyx.groupby('班级')['学号'].agg({'优秀':np.size})

#dfhg中保存各班优秀人数

dftj=pd.merge(dfpj,dfhg,on='班级',how='left')

#以dfpj为基础,以'班级'为连接键,将dfhg连接到dfpj上,生成dftj

dftj=pd.merge(dftj,dfyx,on='班级',how='left')

#以dftj为基础,以'班级'为连接键,将dfyx连接到dftj上

dftj=pd.merge(dftj,dfrs,on='班级',how='left')

#以dftj为基础,以'班级'为连接键,将dfrs连接到dfpj上

dftj['语文']=round(dftj['语文'],2)

dftj['数学']=round(dftj['数学'],2)

dftj['英语']=round(dftj['英语'],2)

dftj['总分']=round(dftj['总分'],2)

dftj['合格']=round((dftj['合格']/dftj['人数'])*100,2)

dftj['优秀']=round((dftj['优秀']/dftj['人数'])*100,2)

dftj=dftj.fillna(0)

#用0填充NaN值

dftj.to_excel('d:/test3.xlsx',sheet_name='Sheet1',index=True)

#将数据框架dftj的数据保存到Excel文件中,索引列'班级'也一并写入

P23-3.py运行后生成的excel表格(test3.xlsx):

相关推荐

探索Java项目中日志系统最佳实践:从入门到精通

探索Java项目中日志系统最佳实践:从入门到精通在现代软件开发中,日志系统如同一位默默无闻却至关重要的管家,它记录了程序运行中的各种事件,为我们排查问题、监控性能和优化系统提供了宝贵的依据。在Java...

用了这么多年的java日志框架,你真的弄懂了吗?

在项目开发过程中,有一个必不可少的环节就是记录日志,相信只要是个程序员都用过,可是咱们自问下,用了这么多年的日志框架,你确定自己真弄懂了日志框架的来龙去脉嘛?下面笔者就详细聊聊java中常用日志框架的...

物理老师教你学Java语言(中篇)(物理专业学编程)

第四章物质的基本结构——类与对象...

一文搞定!Spring Boot3 定时任务操作全攻略

各位互联网大厂的后端开发小伙伴们,在使用SpringBoot3开发项目时,你是否遇到过定时任务实现的难题呢?比如任务调度时间不准确,代码报错却找不到方向,是不是特别头疼?如今,随着互联网业务规模...

你还不懂java的日志系统吗 ?(java的日志类)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

谈谈枚举的新用法--java(java枚举的作用与好处)

问题的由来前段时间改游戏buff功能,干了一件愚蠢的事情,那就是把枚举和运算集合在一起,然后运行一段时间后buff就出现各种问题,我当时懵逼了!事情是这样的,做过游戏的都知道,buff,需要分类型,且...

你还不懂java的日志系统吗(javaw 日志)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

Java 8之后的那些新特性(三):Java System Logger

去年12月份log4j日志框架的一个漏洞,给Java整个行业造成了非常大的影响。这个事情也顺带把log4j这个日志框架推到了争议的最前线。在Java领域,log4j可能相对比较流行。而在log4j之外...

Java开发中的日志管理:让程序“开口说话”

Java开发中的日志管理:让程序“开口说话”日志是程序员的朋友,也是程序的“嘴巴”。它能让程序在运行过程中“开口说话”,告诉我们它的状态、行为以及遇到的问题。在Java开发中,良好的日志管理不仅能帮助...

吊打面试官(十二)--Java语言中ArrayList类一文全掌握

导读...

OS X 效率启动器 Alfred 详解与使用技巧

问:为什么要在Mac上使用效率启动器类应用?答:在非特殊专业用户的环境下,(每天)用户一般可以在系统中进行上百次操作,可以是点击,也可以是拖拽,但这些只是过程,而我们的真正目的是想获得结果,也就是...

Java中 高级的异常处理(java中异常处理的两种方式)

介绍异常处理是软件开发的一个关键方面,尤其是在Java中,这种语言以其稳健性和平台独立性而闻名。正确的异常处理不仅可以防止应用程序崩溃,还有助于调试并向用户提供有意义的反馈。...

【性能调优】全方位教你定位慢SQL,方法介绍下!

1.使用数据库自带工具...

全面了解mysql锁机制(InnoDB)与问题排查

MySQL/InnoDB的加锁,一直是一个常见的话题。例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?下面是不同锁等级的区别表级锁:开销小,加锁快;不会出现死锁;锁定粒度...

看懂这篇文章,你就懂了数据库死锁产生的场景和解决方法

一、什么是死锁加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享锁),修改数据的事务需要获...