前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >精品教学案例 | 利用分类模型预测学生成绩等级

精品教学案例 | 利用分类模型预测学生成绩等级

原创
作者头像
数据酷客
修改2020-05-09 17:28:01
3.1K1
修改2020-05-09 17:28:01
举报

查看本案例完整的数据、代码和报告请登录数据酷客(cookdata.cn)案例板块。

本案例适合作为大数据专业数据科学导引或机器学习实践课程的分类模型章节的实践教学案例。通过本案例,能够达到以下教学效果:

  • 培养学生解决真实问题的能力。基于真实的学生信息和行为特征数据,解决学生成绩预测问题。
  • 加深学生对常用分类模型的理解。具体地,提高K-近邻、逻辑回归、朴素贝叶斯和支持向量机等算法基本原理的认识。
  • 提高动手实践能力。利用Scikit-learn工具,提高学生对上述分类模型的实践能力。

数据来自手机APP"Kalboard 360"的学习管理系统(LMS)。Kalboard 360旨在利用尖端技术来提升学校K12教育的教育水平。数据集由480个学生记录和16个特征组成。这些特征分为三大类:

(1)性别和国籍等人口统计特征。

(2)学历背景特征,如教育阶段,年级和隶属教室。

(3)行为特征,如上课举手,访问资源,家长回答问卷调查,学校满意度等。

该数据集的收集来自两个学期:第一学期收集了245个学生记录,第二学期收集了235个学生记录。最后学生依据其总成绩被分为三类: 低:0-69、中:70-89、高:90-100。我们的任务是根据收集的数据预测学生的成绩等级。

数据字段及说明:

特征

说明

gender

学生性别( 'Male' or 'Female’)

NationalITy

学生国籍

PlaceofBirth

学生的出生地

StageID

受教育水平(‘lowerlevel’,’MiddleSchool’,’HighSchool’)

GradeID

年级(‘G-01’, ‘G-02’, ‘G-03’, ‘G-04’, ‘G-05’, ‘G-06’, ‘G-07’, ‘G-08’, ‘G-09’, ‘G-10’, ‘G-11’, ‘G-12 ‘)

SectionID

隶属的教室(’A’,’B’,’C’)

Topic

课程名

Semester

学校的学期(’ First’,’ Second’)

Relation

监护学生的家长(’mom’,’father’)

raisedhands

学生在教室中举手次数(0-100)

VisITedResources

学生访问在线课程次数(0-100)

AnnouncementsView

学生检查新公告的次数(0-100)

Discussion

学生参加讨论组的次数(0-100)

ParentAnsweringSurvey

家长是否回答了学校提供的调查问卷(’Yes’,’No’)

ParentschoolSatisfaction

家长对学校的满意度(’Yes’,’No’)

StudentAbsenceDays

每个学生的缺勤天数('above-7', 'under-7')

Class

根据学生的总成绩分为三个等级(低分:0-69,中等分数:70-89,高分:90-100)

代码语言:javascript
复制
## 载入必要库
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import BernoulliNB
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier

from sklearn.metrics import confusion_matrix, classification_report, accuracy_score

1. 数据读取

代码语言:javascript
复制
# 导入数据
edm = pd.read_csv('./input/xAPI-Edu-Data.csv')
edm.head()

2. 探索性数据分析

首先,我们来查看一下数据集的基本信息:

代码语言:javascript
复制
## 数据集基本信息
edm.info()

可以看到数据中不存在缺失值,但列名中有些字母大小写不统一,为方便我们统一改为首字母大写,其余小写:

代码语言:javascript
复制
# 修改列名
edm.rename(index=str, columns={'gender':'Gender', 'NationalITy':'Nationality',
                               'raisedhands':'RaisedHands', 'VisITedResources':'VisitedResources'},
                               inplace=True)

接下来我们通过可视化来进一步挖掘数据中包含的信息,首先来看3个成绩等级的数量分布情况:

代码语言:javascript
复制
## 绘制条形图
plt.figure(figsize=(8, 6))
counts = sns.countplot(x='Class', data=edm, palette='coolwarm')
counts.set(xlabel='Class', ylabel='Count', title='Occurences per class')
plt.show()

可以看到虽然成绩中等的学生要比其余两个成绩等级的学生多一些,但数据集不存在类别分布极端不平衡的情况。

继续查看学生的国籍分布情况:

代码语言:javascript
复制
## 绘制条形图
plt.figure(figsize=(8, 6))
nat = sns.countplot(x='Nationality', data=edm, palette='coolwarm')
nat.set(xlabel='Nationality', ylabel='Count', title='Nationality Representation')
plt.setp(nat.get_xticklabels(), rotation=60)
plt.show()

数据集中的学生分别来自14个国家,大多数学生来自科威特或约旦。

下面再来看看两个不同学期间,学生成绩等级的数量分布差异:

代码语言:javascript
复制
## 绘制条形图
plt.figure(figsize=(8, 6))
sem = sns.countplot(x='Class', hue='Semester', order=['L', 'M', 'H'], data=edm, palette='coolwarm')
sem.set(xlabel='Class', ylabel='Count', title='Semester comparison')
plt.show()

学生在第二学期(S)的表现比第一学期(F)好一些。 在第二学期,成绩中等的学生人数保持不变,但是成绩差的学生人数较少,而成绩好的学生人数较多。

接着来看看不同性别之间,学生成绩等级的数量分布差异:

代码语言:javascript
复制
## 绘制条形图
plt.figure(figsize=(8, 6))
plot = sns.countplot(x='Class', hue='Gender', data=edm, order=['L', 'M', 'H'], palette='coolwarm')
plot.set(xlabel='Class', ylabel='Count', title='Gender comparison')
plt.show()

可以看到学生中男生较多,并且较女生而言,低分成绩的人较多,高分成绩的人较少。

再来看看访问在线教学资源次数的多少会不会影响学生的成绩等级:

代码语言:javascript
复制
## 绘制条形图
plt.figure(figsize=(8, 6))
plot = sns.swarmplot(x='Class', y='VisitedResources', hue='Gender', order=['L', 'M', 'H'], 
              data=edm, palette='coolwarm')
plot.set(xlabel='Class', ylabel='Count', title='Gender comparison on visited resources')
plt.show()

上图显示获得低分(L)的学生比获得中等分数(M)或高分(H)的学生访问的资源少的多。此外,获得高分(H)的女性几乎都访问了很多在线资源。

从数据集的基本信息中可以看到,有些特征的类型是字符型,需要在建模前做一些预处理。

3. 数据预处理

首先对字符型特征进行数值编码:

代码语言:javascript
复制
## 选出需要进行数值编码的特征
str_columns = edm.dtypes[edm.dtypes == 'object'].index

## 数值编码
for col in str_columns:
    edm[col] = LabelEncoder().fit_transform(edm[col])

为方便后续建立模型,需要对除去目标特征之外的无序分类特征进行独热编码:

代码语言:javascript
复制
## 独热编码
edm_new = pd.get_dummies(edm, columns=str_columns.drop(['Class', 'StageID']))
代码语言:javascript
复制
## 查看独热编码后的维度
edm_new.shape

最后,将目标与数据分离,准备建立模型:

代码语言:javascript
复制
## 分离目标
X_new = edm_new.drop(['Class'], axis=1)
y_new = edm_new['Class']

4. 建立模型并评估

首先将数据集划分为训练集和测试集,比例为4:3:

代码语言:javascript
复制
X_train,X_test, y_train, y_test = train_test_split(X_new, y_new, 
                                                   test_size=.25, 
                                                   random_state=10, 
                                                   stratify=y_new)

我们首先建立K-近邻、逻辑回归和支持向量机模型,并输出测试集的分类正确率和分类报告:

代码语言:javascript
复制
## 建模并评估
keys = []
scores = []
models = {'K-近邻': KNeighborsClassifier(),
          '逻辑回归': LogisticRegression(),
          '线性支持向量机': LinearSVC(),
          '支持向量机': SVC()}

for k,v in models.items():
    mod = v
    mod.fit(X_train, y_train)
    pred = mod.predict(X_test)
    print(str(k) + '建模效果:' + '\n')
    print(classification_report(y_test, pred, target_names=['H', 'L', 'M']))
    acc = accuracy_score(y_test, pred)
    print('分类正确率:'+ str(acc)) 
    print('\n' + '\n')
    keys.append(k)
    scores.append(acc)
    table = pd.DataFrame({'model':keys, 'accuracy score':scores})

table

从上表看到,K-近邻模型的预测效果较另外三种模型要好。

接下来我们建立决策树和三种朴素贝叶斯模型:

代码语言:javascript
复制
## 建模并评估
keys = []
scores = []
models = {'决策树': DecisionTreeClassifier(),
          '高斯贝叶斯': GaussianNB(),
          '伯努利贝叶斯': BernoulliNB(),
          '多项式贝叶斯': MultinomialNB()}

for k,v in models.items():
    mod = v
    mod.fit(X_train, y_train)
    pred = mod.predict(X_test)
    print(str(k) + '建模效果:' + '\n')
    print(classification_report(y_test, pred, target_names=['H', 'L', 'M']))
    acc = accuracy_score(y_test, pred)
    print('分类正确率:'+ str(acc)) 
    print('\n' + '\n')
    keys.append(k)
    scores.append(acc)
    table = pd.DataFrame({'model':keys, 'accuracy score':scores})

table

上表可以看到决策树、伯努利朴素贝叶斯模型效果较好。

5. 参数调优

我们对两次建模效果比较好的三种模型:K-近邻、决策树、逻辑回归模型(伯努利朴素贝叶斯模型不作调整)进行调参,看看能否进一步提升模型的效果:

5.1 逻辑回归

首先对LogisticRegression类中的参数Cpenaltyclass_weight进行调整:

代码语言:javascript
复制
# 创建一个包含不同C取值的列表
C_grid = [0.2, 0.4, 0.6, 0.8, 1, 1.2, 1.4, 1.6, 1.8]

# 创建一个包含不同penalty取值的列表
penalty_grid  = ["l2", "l1"]

# 创建一个包含不同class_weight取值的列表
class_weight_grid = ['balanced', None]

# 组合成元组列表
parameters=[(C_, penalty_, class_weight_) for C_ in C_grid for penalty_ in penalty_grid for class_weight_ in class_weight_grid]
parameters
代码语言:javascript
复制
## 参数调优
result_accuracy={}
for parameter in parameters:
    result_accuracy[parameter] = LogisticRegression(random_state=0, 
                                                    penalty=parameter[1], 
                                                    C=parameter[0], 
                                                    class_weight=parameter[2]).fit(X_new, y_new).score(X_new, y_new) 
df = pd.DataFrame(list(result_accuracy.items()),
                      columns=['parameter_list', 'accuracy']).sort_values(by='accuracy', ascending=False)[:5]
df.reset_index(drop=True)

当采用L1正则化项,正则化强度为1,且平衡样本分类权重时,模型效果提升最为明显。

5.2 K-近邻

接着我们对KNeighborsClassifier类中的参数n_neighborsweights进行调整:

代码语言:javascript
复制
# 创建一个包含不同n_neighbors取值的列表
k_grid = [1, 2, 3, 4, 5, 6, 7, 8]

# 创建一个包含不同weights取值的列表
weights_grid  = ["uniform", "distance"]

# 组合成元组列表
parameters = [(k_, weights_) for k_ in k_grid for weights_ in weights_grid]
parameters
代码语言:javascript
复制
## 参数调优
result_accuracy={}
for parameter in parameters:
    result_accuracy[parameter] = KNeighborsClassifier(n_neighbors=parameter[0], 
                                                      weights=parameter[1]).fit(X_new, y_new).score(X_new, y_new) 
                                                     
df = pd.DataFrame(list(result_accuracy.items()),
                      columns=['parameter_list', 'accuracy']).sort_values(by='accuracy', ascending=False)[:5]
df.reset_index(drop=True)

可以看到当近邻样本个数为5,K-近邻与加权K-近邻模型效果一致,且与之前持平。

5.3 决策树

最后我们对DecisionTreeClassifier类中的参数criterionmax_depthclass_weight进行调整:

代码语言:javascript
复制
# 创建一个包含不同criterion取值的列表
criterion_grid = ['gini', 'entropy']

# 创建一个包含不同max_depth取值的列表
depth_grid = [1, 2, 3, 4, 5, 6, 7, 8, None]

# 创建一个包含不同class_weight取值的列表
class_weight_grid = ['balanced', None]

# 组合成元组列表
parameters = [(criterion_, depth_, weights_) for criterion_ in criterion_grid for depth_ in depth_grid for weights_ in class_weight_grid]
parameters
代码语言:javascript
复制
## 参数调优
result_accuracy={}
for parameter in parameters:
    result_accuracy[parameter] = DecisionTreeClassifier(criterion=parameter[0], 
                                                        max_depth=parameter[1],
                                                        class_weight=parameter[2],random_state=1).fit(X_train, y_train).score(X_test, y_test) 
                                                     
df = pd.DataFrame(list(result_accuracy.items()),
                      columns=['parameter_list', 'accuracy']).sort_values(by='accuracy', ascending=False)[:5]
df.reset_index(drop=True)

当采用Gini系数计算不纯度,最大树深度设为5且平衡样本分类权重时,模型效果提升最明显, 也是目前的最佳模型,正确率达到了73%。

6. 决策树模型特征重要性排序

我们再次利用选出的最佳参数建立模型,并输出特征重要性:

代码语言:javascript
复制
## 训练模型
model_DF = DecisionTreeClassifier(max_depth=5, class_weight='balanced')
model_DF.fit(X_train, y_train)

## 特征重要性
fea_imp = pd.Series(model_DF.feature_importances_, index=X_train.columns).sort_values(ascending=False)[:5]
fea_imp

可以看到学生缺勤的天数StudentAbsenceDays、访问在线课程次数VisitedResources、举手次数RaisedHands、监护人Relation和检查新公告的次数AnnouncementsView这5个特征最为重要。至此,我们通过探索性数据分析、数据预处理、模型选择和参数调优,最终建立了决策树模型来预测学生的成绩等级。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 查看本案例完整的数据、代码和报告请登录数据酷客(cookdata.cn)案例板块。
  • 1. 数据读取
  • 2. 探索性数据分析
  • 3. 数据预处理
  • 4. 建立模型并评估
  • 5. 参数调优
    • 5.1 逻辑回归
      • 5.2 K-近邻
        • 5.3 决策树
        • 6. 决策树模型特征重要性排序
        相关产品与服务
        大数据
        全栈大数据产品,面向海量数据场景,帮助您 “智理无数,心中有数”!
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档