pythonpandasampampquot数智教育ampampquot数据可视化分析
数据介绍:
数据来源于由宁波教育局与阿里云计算有限公司主办,宁波效实中学承办的"数智教育"数据可视化创新大赛数据集。
https://www.heywhale.com/mw/dataset/5eb3f5f9366f4d002d76e70f1_teacher.csv:包含了近五年各班各学科的教师信息 term:学期 cla_id:班级ID cla_Name:班级名 gra_Name:年级名 sub_id:学科ID sub_Name:学科名 bas_id:教师id bas_Name:教师名 2_studentinfo.csv:包含了当前在校学生详细信息 bf_StudentID,学生ID bf_Name,学生姓名 bf_sex,性别 bf_nation,民族 bf_BornDate,出生日期(年) cla_Name,班级名(与teacher.csv的cla_name对应) bf_NativePlace,家庭住址(省市或省) Bf_ResidenceType,家庭类型 bf_policy,政治面貌 cla_id,班级ID cla_term,班级学期 bf_zhusu,是否住校 bf_leaveSchool,是否退学 bf_qinshihao,宿舍号 3_kaoqin.csv kaoqin_id,考勤ID qj_term,学期 DataDateTime,时间和日期 ControllerID,对应考勤类型表里的ControllerID controler_name,考勤名称 control_task_order_id,对应考勤类型表里的control_task_order_id bf_studentID,学生ID,对应学生信息表 bf_Name,学生姓名 cla_Name,班级名 bf_classid班级ID 4_kaoqintype.csv:考勤类型 controler_id,考勤类型id controler_name,考勤类型名称 control_task_order_id,考勤事件id control_task_name:考勤事件名 5_chengji.csv:学生成绩 mes_TestID,考试id exam_number,考试编码 exam_numname,考试编码名称 mes_sub_id,考试学科id mes_sub_name,考试学科名 exam_term,考试学期 exam_type,考试类型(对应考试类型表) exam_sdate,考试开始时间 mes_StudentID,学生id mes_Score,考试成绩(-1为作弊,-2为缺考,-3为免考) mes_Z_Score,换算成Z-score(Z-score、T-score、等第 是一种学生成绩评价方式,可以参考网络百科) mes_T_Score,换算成T-score mes_dengdi:换算成等第(参见:https://tianchi.aliyun.com/forum/postDetail?spm=5176.12281978.0.0.65ca76d8kaGnld&postId=47777) 6_exam_type.csv:考试类型 EXAM_KIND_ID:考试类型id EXAM_KIND_NAME:考试类型名称 7_consumption.csv:本学年学生消费信息 DealTime,消费时间 MonDeal,消费金额 bf_studentID:对应学生信息表studentid AccName,姓名 PerSex,性别 特别说明: 1.由于人为登记等不可避免原因,某些字段可能存在缺失或者异常值 2.从班级名可以看出,从2017年开始学校陆续启用了新校区,2018年新校区统一命名为型为"白-高二(01)"和"东-高二(01)"的班级名 3.考勤类型中的"校服[移动考勤]"指的是没穿校服3.考勤类型中的"校服[移动考勤]"指的是没穿校服#导入用到的库 import pandas as pd import matplotlib.pyplot as plt
1.各科成绩分布图
结果分析:
1.体育,美术,音乐,通用技术成绩很稳定均匀,与之有关的影响因素较少,在于学生的个人选择及天赋,可不必投入较多资源;
2.该学校的数学,英语,语文平均成绩明显较其他科目成绩好,说明该校的主要的教师资源,人力资源主要集中在三大学科上;
代码:#读取成绩文件 chengji_data=pd.read_csv("5_chengji.csv") #mes_Score,考试成绩(-1为作弊,-2为缺考,-3为免考) 删除以上数据 chengji_data1=chengji_data[chengji_data["mes_Score"]>0] #查看每列空值 chengji_data1.isna().sum() #按课程名分组 chengji_group=chengji_data1.groupby("mes_sub_name") #按学年分组 chengji_group_year=chengji_data1.groupby("exam_term") #建立空表 data=pd.DataFrame({"data":[]}) boxes=[] boxes_name=[] #遍历按课程名分组的所有课程名及成绩 for k,g in chengji_group: if k!="data": boxes.append(g["mes_Score"]) boxes_name.append(k) #全部学年集合 chengji_year=[] for k1,g1 in chengji_group_year: chengji_year.append(k1)
#定义图颜色 color = dict(boxes="DarkGreen", whiskers="DarkOrange", medians="DarkBlue", caps="Gray") plt.rcParams["font.sans-serif"]=["SimHei"]##中文乱码问题! plt.rcParams["axes.unicode_minus"]=False#横坐标负号显示问题! plt.figure(figsize=(10,5)) #图片大小为10*5 plt.boxplot(boxes,whis=2,showmeans=True,showbox = True,labels=boxes_name,showfliers=False) plt.grid(axis="y",alpha=0.4)#绘制 plt.show()
2.历年成绩对比曲线
结果分析:
1.从图上可以看出所有成绩从2013-2015都比较平稳,许多课程从2015年开始成绩开始呈下降趋势;
2.可能跟近年来一直要求的素质教育有关,出题的方式及难度都有问题,以及老师的过往经验的不适用性;
代码:#新建模板以分组日期集合为index data1=pd.DataFrame({"date":chengji_year}) data1.set_index("date", inplace=True)#设置日期为index for k,g in chengji_group:#遍历课程分组 print(k) chengji_group_year=g.groupby("exam_term")#按学年分组取年和平均成绩写入新表 for k_y,g_y in chengji_group_year: print(k_y,g_y) data1.loc[k_y,k]=g_y["mes_Score"].mean()
plt.figure(figsize=(12,5)) #图片大小为12*5 plt.plot(data1,ms=5,marker=".",label=data1.columns) plt.grid(alpha=0.4)#绘制 plt.legend(loc="lower right")#显示图例 plt.show()
3.考试类型与成绩对比分析
结果分析:
1.考试类型与各科成绩波动较大,可能存在明显的难易程度不同;
2.学校的期中期末考试成绩一般分布可以,其他类型考试波动很大;
代码:#读取考试类型表 kaoshi_lx=pd.read_csv("6_exam_type.csv") kaoshi_lx.set_index("EXAM_KIND_ID", inplace=True)#设置类型为index
#按课程分组遍历 for k,g in chengji_group: #print(k) #按考试类型分组 chengji_group_year=g.groupby("exam_type") #取考试类型和平均成绩 for k_y,g_y in chengji_group_year: #print(k_y,g_y) kaoshi_lx.loc[k_y,k]=g_y["mes_Score"].mean() kaoshi_lx
4.政治面貌/民族占比#读取学生信息表 zhengzhi=pd.read_csv("2_student_info.csv") #按政治面貌分组 zhengzhi_group=zhengzhi.groupby("bf_policy").count() #按民族分组 minzu_group=zhengzhi.groupby("bf_nation").count() zhengzhi_group["bf_StudentID"].plot.pie() minzu_group["bf_StudentID"].plot.pie()
5.学生消费信息分布
结果分析:
1.图中可以看出各学生总消费以及每次消费金额都成明显的正态分布,说明该学校整体消费趋势正常
2.该数据统计了6个月(2018.7-2019.1)六个月的消费情况,平均来说该学校学生每月平均消费在[250,500];
3.每次消费金额在7-10之间,但存在可能购买文具等小物件上,这里不做详细的分类讨论;
代码#读取消费信息表 sale=pd.read_csv("7_consumption.csv") sale["DealTime"]=pd.to_datetime(sale["DealTime"])#转换日期格式 ym_mean = sale.groupby([sale.DealTime.dt.year, sale.DealTime.dt.month]).sum() #按月求和 ym_mean["MonDeal"]=abs(ym_mean["MonDeal"]) ym_mean["MonDeal"].plot.bar() #学生消费top sale_top= sale.groupby("bf_StudentID").sum() #按学生求和 sale_top.sort_values(by=["MonDeal"],inplace=True) sale_top["MonDeal"]=abs(sale_top["MonDeal"]) sale_top["MonDeal"].head(20).plot.bar()
6.学生考勤分析
代码#读取考勤表 kaoqin_df=pd.read_csv("3_kaoqin.csv") #使用正则表达式清洗班级名 for i in range(len(kaoqin_df)): str1=re.sub(u"(.*?)|白-|[A-Z]|东-|[0-9]", "",kaoqin_df.loc[i,"cla_Name"]) str1=str1.replace(" ","") kaoqin_df.loc[i,"cla_Name1"]=str1 #取所有考勤汇总 kaoqin_type=kaoqin_df.groupby(["controler_name"]).count() kaoqin_type.index kaoqin_moban=pd.DataFrame({"type":kaoqin_type.index}) kaoqin_moban.set_index("type", inplace=True)#设置类型为index kaoqin_moban#按新的班级名分组 kaoqin_gruop=kaoqin_df.groupby(["cla_Name1"]) #遍历分组 for k,g in kaoqin_gruop: print(k) #按考勤类型汇总 tmp=g.groupby(["controler_name"]).count() for j1 in tmp.index: #print(tmp.loc[j1,"kaoqing_id"]) #根据考勤类型写入新表 kaoqin_moban.loc[j1,k]=tmp.loc[j1,"kaoqing_id"] kaoqin_moban
labels = list(kaoqin_moban.columns) first = list(kaoqin_moban["高一"]) second = list(kaoqin_moban["高二"]) third = list(kaoqin_moban["高三"]) data = [first, second, third] x = range(0,8) width = 0.35 # 将bottom_y元素都初始化为0 bottom_y = [0] * 8 # 计算每组柱子的总和,为计算百分比做准备 sums = [sum(i) for i in zip(first, second, third)] #print(first,labels,sums) plt.figure(figsize=(12,5)) for i in data: # 计算每个柱子的高度,即百分比 y = [a/b for a, b in zip(i, sums)] #print(x,y) plt.bar(x, y, width, bottom=bottom_y) # 计算bottom参数的位置 bottom_y = [(a+b) for a, b in zip(y, bottom_y)] plt.legend(labels,loc="right") plt.xticks(x, kaoqin_moban.index) plt.title("考勤分析") plt.show()
labels = list(kaoqin_moban1.index) da1 = list(kaoqin_moban1["操场考勤机"]) da2 = list(kaoqin_moban1["早退[移动考勤机]"]) da3 = list(kaoqin_moban1["校徽_早退"]) da4 = list(kaoqin_moban1["校服[移动考勤机]"]) da5 = list(kaoqin_moban1["离校[移动考勤机]"]) da6 = list(kaoqin_moban1["进校[移动考勤机]"]) da7 = list(kaoqin_moban1["迟到[移动考勤机]"]) da8 = list(kaoqin_moban1["迟到_晚到"]) data = [da1,da2,da3,da4,da5,da6,da7,da8] x = range(0,3) width = 0.35 # 将bottom_y元素都初始化为0 bottom_y = [0] * 3 # 计算每组柱子的总和,为计算百分比做准备 sums = [sum(i) for i in zip(da1,da2,da3,da4,da5,da6,da7,da8)] #print(first,labels,sums) plt.figure(figsize=(8,6)) for i in data: # 计算每个柱子的高度,即百分比 y = [a/b for a, b in zip(i, sums)] #print(x,y) plt.bar(x, y, width, bottom=bottom_y) # 计算bottom参数的位置 bottom_y = [(a+b) for a, b in zip(y, bottom_y)] plt.legend( kaoqin_moban1.columns,loc="upper center") plt.xticks(x, kaoqin_moban1.index) plt.title("考勤分析") plt.show()