文章目录

  • 前言
  • 一、导入库
  • 二、数据处理
    • 1、用户特征数据标签化
    • 2、用户特征数据与作业表合并
    • 3、计算附加其他信息
    • 4、用户行为数据与作业表合并
    • 5、用户特征行为数据、用户行为数据与作业/考试明细数据合并
  • 三、学生成绩数据分析
    • 1、变量之间相关性分析
    • 2、数据建模
      • 2.1 knn
      • 2.2 Logistic回归
      • 2.3 决策树
      • 2.4 随机森林

前言

该文章为连载的第三篇:学生成绩分析

某家在线教育机构拥有自己开发的教育产品VLE,该教育机构提供了他们四个学期里,开展的七门课的数据,接下来我会根据这些数据,为该教育机构做一系列的数据分析,包括用户的RFM模型、用户分群特征、用户成绩分析等等。

该教育机构部分数据库结构如下


如下这三篇文章为:用户成绩分析

做用户成绩分析,主要是把学生特征和学生使用产品习惯,与成绩结果做关联,所以会用到如下几个表:

  1. studentInfo 学生信息表 (总数据量三万多,记为stu)
  2. studentVle 学生产品交互行为表 (总数据量一千多万,记为vle)
  3. studentAssessment 学生成绩表 (总数据量十七余万,记为stu_ass)
  4. assessments 作业/考试表(总数据量两百多,记为ass)

注意assessment意为作业,但涵盖Exam的考试信息,因为在国外,作业和考试都有一个权重分值,都会占最终成绩的一部分,并不是考试占最终成绩的100%。

用户数据:学生编号,性别,学生居住区,最高学历,多重剥夺指数范围(衡量学生所在区的城市贫富等情况),年龄段,是否残疾,学生尝试该课程次数,当前课程的学分,最终成绩

行为数据:学习时长,点击次数

课程数据:课程编号,开课时间,使用产品的ip编码,作业/考试编号、日期等


一、导入库

import pandas as pd
import numpy as np
import datetime
import time
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS']
matplotlib.rcParams['axes.unicode_minus']=False
import matplotlib.pyplot as plt
import seaborn as sns
import sklearn
from sklearn.preprocessing import LabelEncoder
np.set_printoptions(suppress=True)
pd.set_option('display.float_format', lambda x: '%.4f' % x)

二、数据处理

1、用户特征数据标签化

用df.isna().sum()的方法,查看三个表的空缺值情况

学生信息表里:
只有多重剥夺指数范围有1111条空值(总数据量32593,空缺占比3.4%)

学生成绩表里:
只有分数有173条空缺值,总数据量173912,空缺占比极低,会用该学期该门课的平均值填补。

考试或作业表:
只有考试日期有11条空缺值,是因为部分考试/作业无日期限制。

先看一下学生信息表大概长什么样子

把object类型的重要字段标签化

#性别
stu["gender"]=stu["gender"].map({"M":1,"F":2})#最高教育程度
highest_education_dict={"No Formal quals":0,"Lower Than A Level":1,"A Level or Equivalent":2,"HE Qualification":3,"Post Graduate Qualification":4}
stu["highest_edu_label"]=stu['highest_education'].map(highest_education_dict)#多重剥夺指数范围#先去中间值,把范围转成数值
imd_band_dict={'0-10%':5,
'10-20':15,
'20-30%':25,
'30-40%':35,
'40-50%':45,
'50-60%':55,
'60-70%':65,
'70-80%':75,
'80-90%':85,
'90-100%':95}
stu["imd_band_label"]=stu['imd_band'].map(imd_band_dict)#平均数填补空值
stu["imd_band_label"].fillna(stu["imd_band_label"].mean(),inplace=True)#年龄:
age_encoder = LabelEncoder()
age_encoder.fit(stu['age_band'].value_counts().sort_index().index.tolist())
stu["age_band_label"]=age_encoder.transform(stu['age_band'])#是否残疾
stu["disability"]=stu["disability"].map({"Y":1,"N":0})#最终成绩
stu["final_result_label"]=stu["final_result"].map({'Withdrawn':0, 'Fail':1,'Pass':2, 'Distinction':3})

筛选所需要的数据:

stu=stu[["code_module","code_presentation","id_student","gender","num_of_prev_attempts","studied_credits","disability","highest_edu_label","imd_band_label","age_band_label","final_result_label"]]

2、用户特征数据与作业表合并

合并考试作业表个学生成绩表

stu_ass=pd.merge(stu_ass,ass,on="id_assessment")plt.figure(figsize=(8, 6))
#sns.set_style('white')
sns.boxplot(x="code_presentation", y="score", hue="code_module", data=stu_ass.sort_values("code_presentation"))
plt.legend(loc=0,bbox_to_anchor=(1, 0.8),title="课程",frameon=False)#图示靠右显示
plt.title("各学期各课程考试/作业分数分布")
plt.xlabel("学期")
plt.tight_layout()
plt.show


每学期每门课程均有分数低的异常值,并且较多
BBB和GGG课程的分数,在三个学期中都是大多数同学集中高分位置
CCC和DDD课程的分数集中在较低分数

看一下整体分数分布

sns.distplot(stu_ass["score"],kde=False)
plt.title("整体学生作业/考试分数分布")
plt.show()

看整体的话异常值并不多,大多数分数都分布在60-100之间。0分、40分、60分、80分、100分都有相对于附近的分数值分布突然变集中。

stu_ass["score"].value_counts().sort_index().head(30)

但确实低分每个分数都有并且很集中

用盖帽法处理异常,考虑每学期每门课的难度或许不同,分数分布情况也会不同。这里每学期每门课的的低分异常值定义为:中位数-2倍标准差,

只有


stu_ass["score_chuli"]=stu_ass["score"]#定义一个方法
def yichang(code_pre,code_module):score_list=stu_ass[(stu_ass["code_presentation"]==code_pre)&(stu_ass["code_module"]==code_module)]["score"]s_mean = score_list.mean()s_min = score_list.mean() - 2*score_list.std() stu_ass.loc[(stu_ass["code_presentation"]==code_pre)&(stu_ass["code_module"]==code_module)&(stu_ass["score"] < s_min), 'score_chuli'] = s_minstu_ass.loc[(stu_ass["code_presentation"]==code_pre)&(stu_ass["code_module"]==code_module)&(stu_ass["score"].isna()), 'score_chuli'] = s_mean#每学期每门课
for m in stu_ass["code_presentation"].unique().tolist():for n in stu_ass["code_module"].unique().tolist():yichang(m,n)

修改后的各学期各门课程的分数分布:

3、计算附加其他信息

加上交付时间与应交时间的间隔、和是否准时提交:

stu_ass["day_gap"]=stu_ass["date_submitted"]-stu_ass["date"]stu_ass["submit_on_time"]=stu_ass["day_gap"].apply(lambda x:1 if x<=0 else 0)

4、用户行为数据与作业表合并

每个用户在每学期每门课使用产品用了多少天,总的点击次数是多少

vle_df=vle.groupby(["code_presentation","code_module","id_student"]).agg({"date":pd.Series.nunique,"sum_click":"sum"}).reset_index().rename(columns={"date":"cnt_study_days"})vle_df["avg_click"]=vle_df["sum_click"]/vle_df["cnt_study_days"]stu_vle=pd.merge(stu,vle_df,on=["code_module","code_presentation","id_student"],how="left")stu_vle.isna().sum()

聚合后发现有些用户并没有使用产品,导致该用户的cnt_study_days、sum_click和avg_click为nan,用fillna(0)填补

5、用户特征行为数据、用户行为数据与作业/考试明细数据合并

stu_ass_vle=pd.merge(stu_ass,stu_vle,on=["id_student","code_module","code_presentation"],how="left")

得到一个173912行, 24列的数据集,每一行代表一个学生在一个学期里的一门课的作业/考试情况,以及对应的该学生的特征和使用产品情况。

三、学生成绩数据分析

1、变量之间相关性分析

这里想分析学生的平时分数(作业/考试分数)和最终总分与其他特征会不会有什么相关性。这里用热力图表示。

#筛选出带标签的变量,建模需要使用
train_df=stu_ass_vle[["weight","day_gap","gender","num_of_prev_attempts","studied_credits","cnt_study_days","avg_click","highest_edu_label","imd_band_label","age_band_label","score_chuli","final_result_label"]]corr_data=train_df.drop("id_student",axis=1).corr().round(4)plt.figure(figsize=(12, 12))# np.zeros_like() 返回一个零数组,其形状和类型与给定的数组相同;
mask = np.zeros_like(corr_data)#np.triu_indices_from(mask) 返回数组上三角形的索引。
mask[np.triu_indices_from(mask)] = True
sns.heatmap(corr_data, cmap='viridis',annot=True,fmt='g',mask=mask)
#fmt='g'保持数据小数一致

这里看到很多特征两两之间都没有太多很强的相关性,最后一行的最终成绩可以看到:
每天使用产品越多的学生最终成绩可能越高。
最高学历越高的学生最终成绩可能越高。
平时成绩越好的学生最终成绩可能越高。

其余比较明显相关性的是:
交付作业/考试的间隔时间越大,这个作业/考试的权重可能越高。
重修课程的用户学分会更高。
使用产品天数也多的用户,相对日均点击产品去学习也会越高。
产品日均使用次数越高的,交作业会越早。
女性日均使用产品比男性高

2、数据建模

我们选择使用以下几种模型进行建置,并比较模型的分类效能。

首先在将训练集划分为训练集和验证集,其中训练集用于训练模型,验证集用于验证模型效果。首先导入建模库:


from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier# 预处理
from sklearn.preprocessing import StandardScaler, MinMaxScaler# 模型评估
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import confusion_matrix, classification_report, accuracy_score, f1_score, roc_auc_score

凭经验、以及从上面跟最终成绩跟其他变量的相关性挑出一些重要的指标,并划分特征和标签,并采用分层抽样的方式划分训练集和验证集。

train_df=train_df[["id_student","gender","num_of_prev_attempts","cnt_study_days","avg_click","highest_edu_label","imd_band_label","age_band_label","final_result_label"]]# 划分特征和标签
X = train_df.drop(['id_student', 'final_result_label'], axis=1)
y = train_df['final_result_label'] # 划分训练集和验证集(分层抽样)
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0)
print(X_train.shape, X_val.shape, y_train.shape, y_val.shape)
#(139129, 7) (34783, 7) (139129,) (34783,)

2.1 knn

# 建立knn
knn = KNeighborsClassifier(n_neighbors=4, n_jobs=-1)
#ovo_knn=OneVsOneClassifier(knn)
knn.fit(X_train, y_train)y_pred = knn.predict(X_val)#print('Simple KNeighborsClassifier accuracy:%.3f' % (ovo_knn.score(y_val, y_pred)))print('Simple KNeighborsClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred)))
print('Simple KNeighborsClassifier f1_score: %.3f' % (f1_score(y_val, y_pred,average='macro')))  
Simple KNeighborsClassifier accuracy:0.953
Simple KNeighborsClassifier f1_score: 0.914

2.2 Logistic回归

lr = LogisticRegression(multi_class='multinomial')
lr.fit(X_train, y_train)y_pred = lr.predict(X_val)print('Simple LogisticRegression accuracy:%.3f' % (accuracy_score(y_val, y_pred)))
print('Simple LogisticRegression f1_score: %.3f' % (f1_score(y_val, y_pred,average='macro')))
Simple LogisticRegression accuracy:0.613
Simple LogisticRegression f1_score: 0.203

2.3 决策树

dtc = DecisionTreeClassifier(max_depth=10, random_state=0)
dtc.fit(X_train, y_train)y_pred = dtc.predict(X_val) print('Simple DecisionTreeClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred)))print('Simple DecisionTreeClassifier f1_score: %.3f' % (f1_score(y_val, y_pred,average='macro')))  
Simple DecisionTreeClassifier accuracy:0.657
Simple DecisionTreeClassifier f1_score: 0.394

2.4 随机森林

rfc = RandomForestClassifier(n_estimators=100, max_depth=10, n_jobs=-1)
rfc.fit(X_train, y_train)y_pred = rfc.predict(X_val) print('Simple RandomForestClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred)))
print('Simple RandomForestClassifier f1_score: %.3f' % (f1_score(y_val, y_pred,average='macro')))
Simple RandomForestClassifier accuracy:0.658
Simple RandomForestClassifier f1_score: 0.350

综上,以f1-score作为评价标准的情况下,KNN算法有较好的分类效能,同时可以通过参数调整的方式来优化其他模型,通过调整预测的门槛值来增加预测效能等其他方式。


[Python]学生成绩分析, 可视化以及建模--在线教育行业分析案例连载3相关推荐

  1. python数据分析学生成绩查询系统_python数据分析-学生成绩分析

    python数据分析-学生成绩分析 python数据分析-学生成绩分析 目标:分析学生成绩的影响因素 1.导入原始数据,以及需要用到的库 import pandas as pd import nump ...

  2. 机器学习实战4-教育领域:学生成绩的可视化分析与成绩预测-详细分析

    大家好,我是微学AI,今天给大家带来机器学习实战4-学生成绩的可视化分析与成绩预测,机器学习在教育中的应用具有很大的潜力,特别是在学生成绩的可视化分析与成绩预测方面. 机器学习可以通过对学生的父母教育 ...

  3. (附源码)python学生成绩管理系统 毕业设计 061011

    python学生成绩管理系统的设计与实现 摘 要 随着互联网趋势的到来,各行各业都在考虑利用互联网将自己推广出去,最好方式就是建立自己的互联网系统,并对其进行维护和管理.在现实运用中,应用软件的工作规 ...

  4. 学生成绩分析管理系统

    一.开发目的 随着现代化社会的发展,每年都会有大量苦读寒窗的考生参加高考,但是由于竞争压力大,很多考生由于成绩不理想不能报考自己心仪的高等院校,一方面是由于自身能力不足,另一方面,在平常学习过程种,教 ...

  5. 用access做考场桌贴_利用Word、Excel、Access进行考务安排及学生成绩分析的有效途径-教育文档...

    利用 Word . Excel . Access 进行考务安排及学生成绩 分析的有效途径 一 问题的提出 在新课改教学评价过程中,学生考试评价扮演着重要的角 色. 考试安排的科学性和有效性是评价的基础 ...

  6. 查找和排序算法的学生成绩分析实验

    基于查找和排序算法的学生成绩分析实验 一.实验内容 二.实验原理 三.实验代码记录 四.实验结果 一.实验内容 编写程序将自己学号后面的8位同学的学号.姓名以及数学.英语和数据结构的成绩信息保存到学生 ...

  7. 3+1+2模式excel学生成绩分析模板探讨

    一.引言 设计的学生成绩分析模板的初衷是不动用VBA编写excel文件,增加文件可读性,迁移性,执行性.同时,设计全科分析模式,使其有成绩者均可以依据不同的模式从而能进行成绩分析 二.设计的小样 基本 ...

  8. java学生成绩分析系统spring源码

    开发工具:idea (eclipse) 环境:jdk1.8  mysql 数据库库连接工具 navcat 学生成绩分析系统 系统主要使用技术 • Struts2--请求响应 • Spring--jav ...

  9. 成绩分析系统c语言,学生成绩分析及排名系统C语言程序设计课程设计实习报告...

    学生成绩分析及排名系统C语言程序设计课程设计实习报告 长江大学计算机上机实习报告题目学生成绩分析及排名系统姓名学院__专业班级学号指导教师20120222目录一设计目的1二课程设计摘要2三课程设计的任 ...

  10. python制作成绩分析系统_python实现学生成绩测评系统

    本文实例为大家分享了python实现学生成绩测评系统的具体代码,供大家参考,具体内容如下 1.问题描述(功能要求): 根据实验指导书要求,完成相关软件系统的设计,要求内容翔实,条理清晰,图文并茂(流程 ...

最新文章

  1. C++中的动态内存分配
  2. linux 下的 多线程http 下载器
  3. Datatable删除行的Delete和Remove方法介绍
  4. haproxy 作为反向代理被攻击
  5. 银行大数据风控平台的建设要点与应用
  6. php函数声明提前,php的日期处理函数及uchome的function_coomon中日期处理函数的研究...
  7. vue点击input框出现弹窗_使用vue实现各类弹出框组件
  8. 90年代中国人一个月挣多少钱?一组数据带你看懂90年代消费情况
  9. Hls之TS流分离音视频
  10. linux latex编译器,在Ubuntu系统中下载安装LaTeX编辑器TeXstudio的方法
  11. 中国石油大学OJ 第五场个人训练赛 所罗门王的宝藏
  12. vue项目报错[Vue warn]: Property “visible“ must be accessed with “$data.visible“ because properties start
  13. 华为/华三交换机配置NTP时钟同步
  14. 面试-android
  15. MIT算法导论03-分治法
  16. Internet Explorer 编程简述(序)
  17. mysql实体指的是_数据库中,实体是指( )。
  18. 不忘初心,方得始终——NOIP2016前的感悟
  19. C语言娱乐项目————4、一箭双心
  20. 计算机毕业设计PHP基于Web的软考题库平台(源码+程序+VUE+lw+部署)

热门文章

  1. MDIO总线介绍 |CSDN创作打卡
  2. sl400通过ac无法连接psk加密无线网络
  3. 魔兽单机服务器修改升级属性,魔兽世界单机版怎么调整人物级别(用户使用)?20分...
  4. JASS随机物品系统
  5. python保存网页上的图片_使用Python保存网页上的图片或者保存页面为截图
  6. teraterm 执行sql_teraterm自动或定时执行远程命令
  7. 关于南宁市教育云网站的网课视频链接blob加密破解
  8. 赋能未来的昆腾全新Scalar存储平台
  9. python交通流预测算法_使用KNN方法进行的短时交通流预测和结果分析
  10. 含金量高文科竞赛信息资料