利用Python分析学生成绩
- 一、题目描述
- 二、解题步骤
- 运行环境
- 题目分析
- 三、完整代码
- 四、运行结果
- 五、参考文献
- 附录
- 附录A
- 更新记录
- 附录B 相关练习题目
- 练习一:读取Excel文件数据表分别存入DataFrame对象Score和Duty
- 练习二:自定义数据,完成直方图,折线图,散点图,饼图等
一、题目描述
个人构造一个30名学生的班级,每名学生有三门课程,学生的学号和各门成绩形如:
学号 高数 英语 Python
1001 85 90 96
1002 96 92 95
1003 78 87 83
为了输入数据方便,请保存在如student_score.csv文件中。
(1)请计算三门课程的总分,此班级每门课程的平均分和最高分及最低分,并绘制相应的图形来统计三门课程的成绩分布。
(2)各图形自拟。
(3)坐标轴标签,图例等属性设置完整。
(4)使用中文标题及标签。
二、解题步骤
运行环境
Anconda3.X Spyder(Python 3.7)
题目分析
步骤一:创建csv文件以保存实验所需数据。
本文使用使用Excel创建CSV文件。操作步骤如下:
1)新建一个Excel表,(使用WPS和Microsoft都是一样的)
2)打开Excel进行编辑。
3)生成.csv文件。
方式一:WPS表格-另存为-其它格式-选择文件类型-命名文件名,最后保存。
方式二:保存文档后直接修改“新建 Microsoft Excel 工作表.xlsx”为“使用Excel创建CSV文件.csv”。
4)点击保存后有相应警告提醒,则选“确定”或“是”即可
本文使用到的资源(百度网盘)
链接:https://pan.baidu.com/s/1gKDtK2yNfPgj_2OIzWI0TA
提取码:8vnx
步骤二:导入所需要的库
import pandas as pd #进行文件读取
import matplotlib.pyplot as plt #绘图
步骤三:读取csv文件
在Spyder中读取student_score.csv为DataFrame字符流,并且赋值给df,需要设置编码格式为GBK格式。本文将数据文件放置在同一目录下。作者在使用UFT-8编码会无法正确读出数据。
score = pd.read_csv('./student_score.csv',encoding = 'gbk')#这里使用的是相对路径
#获取文件绝对路径
#import os
#file_path = os.path.abspath('students_score.csv')
#print(file_path)
步骤四:提取所需数据
此步骤中涉及到DataFrame的一些操作。本文在提取相关数据时使用访问属性的方式访问DataFrame单列数据。在附录B中有使用字典访问内部数据的方式访问DataFrame单列数据。
score = pd.read_csv('./student_score.csv',encoding = 'gbk')
#最高分
Math_Max = score.高数.max()
English_Max = score.英语.max()
Python_Max = score.Python.max()
#最低分
Math_Min = score.高数.min()
English_Min = score.英语.min()
Python_Min = score.Python.min()
#成绩方差
Math_Var = score.高数.var()
English_Var = score.英语.var()
Python_Var = score.Python.var()
#成绩均值
Math_Avg = score.高数.mean()
English_Avg = score.英语.mean()
Python_Avg = score.Python.mean()
#学生总成绩
Total_Score = score.高数 + score.英语 + score.Python
步骤五:设置字体
由于默认的pyplot字体并不支持中文字符的显示,因此需要通过设置font.sans-serif参数来改变绘图时的字体,使得可以正常显示中文。同时,由于更改字体后会导致坐标轴中的字体无法显示,因此要同时更改axes.unicode_minus参数
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
步骤六:数据可视化
本文只列出了所有学生总成绩的直方图,折线图,散点图和每门课程的箱线图,其他部分的图形数据较少只给出直方图。其他的绘图在附录B中有相关代码参考。
plt.title('学生总成绩分布直方图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.bar(score.学号,Total_Score)
plt.show()
plt.title('学生总成绩分布折线图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.plot(score.学号,Total_Score)
plt.show()
plt.title('学生总成绩分布散点图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.scatter(score.学号,Total_Score)
plt.show()
plt.title('每门课程箱线图')
plt.xlabel('课程名')
plt.ylabel('分数')
label = ['高数','英语','Python']
s = (score.高数,score.英语,score.Python)
plt.boxplot(s,labels = label)
plt.show()
plt.title('每门课程平均分直方图')
plt.xlabel('课程名')
plt.ylabel('平均分')
plt.bar('Python',Python_Avg)
plt.bar('高数',Math_Avg)
plt.bar('英语',English_Avg)
plt.show()
plt.title('每门课程最高分直方图')
plt.xlabel('课程名')
plt.ylabel('最高分')
plt.bar('Python',Python_Max)
plt.bar('高数',Math_Max)
plt.bar('英语',English_Max)
plt.show()
plt.title('每门课程最低分直方图')
plt.xlabel('课程名')
plt.ylabel('最低分')
plt.bar('Python',Python_Min)
plt.bar('高数',Math_Min)
plt.bar('英语',English_Min)
plt.show()
也可以通过创建子图的方式显示,此时需要创建画布。
p1=plt.figure()#创建画布
a1=p1.add_subplot(2,2,1)#绘制第一幅子图
plt.title('学生总成绩分布直方图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.bar(score.学号,Total_Score)
a2=p1.add_subplot(2,2,2)#绘制第二幅子图
plt.title('学生总成绩分布折线图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.plot(score.学号,Total_Score)
a3=p1.add_subplot(2,2,3)#绘制第三幅子图
plt.title('学生总成绩分布散点图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.scatter(score.学号,Total_Score)
a4=p1.add_subplot(2,2,4)#绘制第四幅子图
plt.title('每门课程箱线图')
plt.xlabel('课程名')
plt.ylabel('分数')
label = ['高数','英语','Python']
s = (score.高数,score.英语,score.Python)
plt.boxplot(s,labels = label)
plt.show()
三、完整代码
import pandas as pd
import matplotlib.pyplot as plt
#读取文件
score = pd.read_csv('./student_score.csv',encoding = 'gbk')
#最高分
Math_Max = score.高数.max()
English_Max = score.英语.max()
Python_Max = score.Python.max()
#最低分
Math_Min = score.高数.min()
English_Min = score.英语.min()
Python_Min = score.Python.min()
#成绩方差
Math_Var = score.高数.var()
English_Var = score.英语.var()
Python_Var = score.Python.var()
#成绩均值
Math_Avg = score.高数.mean()
English_Avg = score.英语.mean()
Python_Avg = score.Python.mean()
#学生总成绩
Total_Score = score.高数 + score.英语 + score.Python
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.title('学生总成绩分布直方图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.bar(score.学号,Total_Score)
plt.show()
plt.title('学生总成绩分布折线图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.plot(score.学号,Total_Score)
plt.show()
plt.title('学生总成绩分布散点图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.scatter(score.学号,Total_Score)
plt.show()
plt.title('每门课程箱线图')
plt.xlabel('课程名')
plt.ylabel('分数')
label = ['高数','英语','Python']
s = (score.高数,score.英语,score.Python)
plt.boxplot(s,labels = label)
plt.show()
plt.title('每门课程平均分直方图')
plt.xlabel('课程名')
plt.ylabel('平均分')
plt.bar('Python',Python_Avg)
plt.bar('高数',Math_Avg)
plt.bar('英语',English_Avg)
plt.show()
plt.title('每门课程最高分直方图')
plt.xlabel('课程名')
plt.ylabel('最高分')
plt.bar('Python',Python_Max)
plt.bar('高数',Math_Max)
plt.bar('英语',English_Max)
plt.show()
plt.title('每门课程最低分直方图')
plt.xlabel('课程名')
plt.ylabel('最低分')
plt.bar('Python',Python_Min)
plt.bar('高数',Math_Min)
plt.bar('英语',English_Min)
plt.show()
四、运行结果
通过创建子图的方式显示:
五、参考文献
黄红梅,张良均.Python数据分析与应用[M].北京:人民邮电出版社,2018(4):52-89
python 计算均值、方差、标准差 Numpy,Pandas
附录
附录A
更新记录
2021-05-04
新增:自定义数据,完成直方图,折线图,散点图,饼图等。
使用字典访问内部数据的方式访问DataFrame单列数据。
读取Excel文件数据表。请参考附录B 相关练习题目
2021-05-24
新增:附录B运行截图。
更改:文中部分描述错误。
2021-06-18
新增:文中正文与附录中的测试代码文件,正文文件为网盘连接。
附录B 相关练习题目
练习一:读取Excel文件数据表分别存入DataFrame对象Score和Duty
题目描述
1.练习pandas统计分析基础,数据读取、分析、输出。
2.自建EXCEL文件,分为2个工作区,分别存放学生信息表(不少于30人)和班级职务表(不少于4种职务)。
如信息表:
学号 姓名
性别 数学 英语 Python 通信技术
1001 张三 男 95 86 87 90
1002 李四 女 98 84 88 89
如班级职务表:
学号 职务
1001 班长
1002 学习委员
读取Excel文件数据表分别存入DataFrame对象Score和Duty。要求如下:
1)Score对象新增一列“总分”为前四列成绩之和。
2)Score对象依据“总分”列的值从高到低进行排序。
3)Score对象根据性别列进行分组,输出男女生各自的平均分。
4)输出男女生的最高分。
5)Score对象新增一列“等级”,总分大于360的等级为A,总分小于270的等级为C,介于270到360之间为B。
6)以“学号”列为关联关键,将Score对象和Duty对象合并,保留所有Score对象的数据行,合并声称新的DataFrame对象Students。
7)把Students对象数据存入新的Excel文件students.xlsx中。
参考代码
请注意在#Anaconda 3.7版本中 ‘sheetname’ 命令,已更新为 ‘sheet_name’
如果有报错:TypeError: read_excel() got an unexpected keyword argument 'sheetname'
请尝试将’sheetname‘改为’sheet_name’
import pandas as pd
Score = pd.read_excel('./class.xlsx')
#TypeError: read_excel() got an unexpected keyword argument `sheetname`
#Anaconda 3.7版本中 'sheetname' 命令,已更新为 'sheet_name'
Duty = pd.read_excel('./class.xlsx',sheet_name=1)
Score['总分'] = Score['数学'] + Score['英语'] + Score['Python'] + Score['通信技术']
Score = Score.sort_values(by='总分',ascending=False)
newgroup = Score[['性别','数学','英语','Python','通信技术','总分']].groupby( by ='性别')
print(newgroup.mean())
print(newgroup.max())
Score['等级'] = Score['总分'].apply(lambda x: 'A' if x>=360 else('C' if x<270 else 'B'))
#print(Score)
#print(Duty)
Students = pd.merge(left=Score , right=Duty , how="outer",on='学号')
#Students = pd.concat([Score,Duty],axis=1,join='inner')
print(Students)
Students.to_excel('./students.xlsx')
运行结果
数学 英语 Python 通信技术 总分
性别
女 81.823529 88.588235 89.176471 80.941176 340.529412
男 87.722222 88.055556 89.944444 78.833333 344.555556
数学 英语 Python 通信技术 总分
性别
女 99 97 99 91 362
男 97 98 99 94 362
学号 性别 数学 英语 Python 通信技术 总分 等级 职务
0 1035 男 89 95 84 94 362 A 体育委员
1 1030 女 84 90 99 89 362 A 纪律委员
2 1010 男 94 89 99 79 361 A 无
3 1034 男 88 94 83 93 358 B 无
4 1029 女 83 89 98 88 358 B 心理委员
5 1009 男 93 88 98 78 357 B 无
6 1028 女 82 88 97 87 354 B 心理委员
7 1033 男 87 93 82 92 354 B 无
8 1008 男 92 87 97 77 353 B 学习委员
9 1015 女 99 94 84 74 351 B 无
10 1027 男 81 87 96 86 350 B 无
11 1032 女 86 92 81 91 350 B 无
12 1007 男 91 86 96 76 349 B 学习委员
13 1014 女 98 93 83 73 347 B 无
14 1026 女 80 86 95 85 346 B 无
15 1006 男 90 85 95 75 345 B 无
16 1013 男 97 92 82 72 343 B 无
17 1025 女 79 85 94 84 342 B 无
18 1005 男 89 84 94 74 341 B 无
19 1012 男 96 91 81 71 339 B 无
20 1024 女 78 84 93 83 338 B 无
21 1019 男 73 98 88 78 337 B 宣传委员
22 1004 男 88 83 93 73 337 B 无
23 1031 女 85 91 70 90 336 B 纪律委员
24 1011 男 95 90 80 70 335 B 无
25 1023 女 77 83 92 82 334 B 无
26 1018 女 72 97 87 77 333 B 无
27 1003 男 87 82 92 72 333 B 班长
28 1022 女 76 82 91 81 330 B 无
29 1002 女 86 81 91 71 329 B 无
30 1017 女 71 96 86 76 329 B 无
31 1021 男 75 81 90 80 326 B 心理委员
32 1016 女 70 95 85 75 325 B 无
33 1001 女 85 80 90 70 325 B 无
34 1020 男 74 80 89 79 322 B 宣传委员
练习二:自定义数据,完成直方图,折线图,散点图,饼图等
参考代码
import pandas as pd
import matplotlib.pyplot as plt
stu = pd.read_excel('./class.xlsx')
stu_Score = stu['数学'] + stu['英语'] + stu['Python'] + stu['通信技术']
stu['总分'] = stu_Score
print(stu)
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.title('学生总成绩分布直方图')
plt.xlabel('学号')
plt.ylabel('总分')
plt.bar(stu['学号'],stu['总分'])
plt.show()
plt.title('学生成绩分布折线图')
plt.xlabel('学号')
plt.ylabel('分数')
plt.plot(stu['学号'],stu['总分'],'r-',stu['学号'],stu['数学'],'b-',stu['学号'],stu['英语'],'y--',
stu['学号'],stu['Python'],'g',stu['学号'],stu['通信技术'],'m-')
plt.legend(['总分','数学','英语','Python','通信技术'])
plt.show()
plt.title('学生成绩分布散点图')
plt.xlabel('学号')
plt.ylabel('分数')
plt.scatter(stu['学号'],stu['总分'])
plt.scatter(stu['学号'],stu['数学'])
plt.scatter(stu['学号'],stu['英语'])
plt.scatter(stu['学号'],stu['Python'])
plt.scatter(stu['学号'],stu['通信技术'])
plt.legend(['总分','数学','英语','Python','通信技术'])
plt.show()
plt.title('学生成绩饼图')
label = ['数学','英语','Python','通信技术']
X = [stu['数学'].sum(),stu['英语'].sum(),stu['Python'].sum(),stu['通信技术'].sum()]
plt.pie(X,labels=label,autopct='%1.2f%%')
plt.show()
运行结果