基于Python学生成绩数据仓库的分析预测系统

目 录
一、绪论 1
(一)选题背景 1
(二)国内外研究现状 1
(三)论文的主要研究内容与意义 3
(四)论文的架构 3
二、数据仓库在成绩分析中的应用与设计 4
(一)数据仓库 4
(二)学生成绩数据仓库概述 7
(三)学生成绩数据仓库的概念模型设计 7
(四)学生成绩数据仓库的逻辑模型设计 8
(五)学生成绩数据仓库的物理模型设计 10
(六)学生成绩数据仓库的数据加载 11
三、数据挖掘技术综述 12
(一)数据挖掘 12
(二)关联规则 13
(三)决策树算法 15
(四)其他数据挖掘算法 18
四、关联规则和决策树组合算法在学生成绩分析中的应用 18
(一)关联规则和决策树组合算法概述 18
(二)关联规则在学生成绩分析中的应用 19
(三)关联规则与决策树组合算法在学生课程成绩分析中的应用 24
五、总结与展望 28
主要参考文献 29
附录 31

(二)学生成绩数据仓库概述

本论文决定采用数据仓库支持下文的数据挖掘,原因有三。一是考虑到数据仓库的面向主题性与非易失性,面向主题便于用户快速查询其需求的信息,而非易失性则保证了数据在数据库中的稳定存储。二是为了充分利用本校信管专业历年来积累的海量学生、教师、课程和成绩的相关数据,这是因为,一方面,数据仓库能够反映历史变化,有利于随时间变化的历史数据的存储;另一方面,学生成绩不但能够反映学生的学习状态,而且能够反映课程安排得合理与否以及教师的授课水平等多方面的情况。三是采用数据仓库技术能够实现对数据的 ETL 操作,即数据抽取、数据转换、数据加载等操作,这样能够实现多方面的数据集成。综上所述,采用数据仓库技术,能够充分挖掘学生成绩中的价值信息,为本校的教务管理提供数据支持。
前文已经介绍了数据仓库技术的基本概念,那么接下来将介绍的是如何实现学生成绩数据仓库的搭建,为下文的数据挖掘提供合适的数据集。众所周知,数据仓库设计最为核心的部分就是模型设计,包括概念模型设计、逻辑模型设计和物理模型设计。下文本论文将从这几个方面一一设计,最后再完成数据加载。

(三)学生成绩数据仓库的概念模型设计

我们知道,概念模型设计是现实世界到信息世界的第一层抽象,它是面向用户的数据模型,也是面向现实世界的数据模型,而并未涉及 DBMS 的一些技术性问题,典型的概念模型有 E-R 模型,本论文也采用的是 E-R 模型。本文转载自http://www.biyezuopin.vip/onews.asp?id=14626因此,在概念模型设计过程中,我们要做的工作包含两个部分,一是确定主题域并划分各个主题域的边界,二是构建E-R 模型。
1.确定主题域
前文对数据仓库的介绍中已经提到,数据仓库是面向主题的,即按照主题域模型进行组织的2。一方面,考虑到学生成绩不但能够反映学生的学习状态,而且能够反映课程安排得合理与否以及教师的授课水平等多方面的情况;另一方面,考虑到本校信息与安全工程学院信管专业历年来积累的学生成绩的相关数据量庞大,作者决定利用学生、教师、课程、专业等多方面的数据构建学生成绩数据仓库。
(1)事实
前文对数据仓库的介绍中已经提到,事实表用来挖掘分析的目标数据的全量信息,故事实指的是用户决策时使用的目标数据。因此,在学生成绩数据仓库中,事实指的是学生成绩。
(2)维度
前文对数据仓库的介绍中已经提到,维表则是对事实表中事件的要素的描述信息,或者称之为属性, 也就是用户观察该事务的角度,记录的一般为基本属性信息。因此,在学生成绩数据仓库中,维度指的是事实的不同考察角度,即学生信息维、专业信息维、课程信息维和教师信息维。

# -*- coding: utf-8 -*-
"""
Created on Wed Apr  4 16:06:13 2018

@author: Administrator
"""

class Node:  
    '''''Represents a decision tree node. 
     
    '''  
    def __init__(self, parent = None, dataset = None):  
        self.dataset = dataset # 落在该结点的训练实例集  
        self.result = None # 结果类标签  
        self.attr = None # 该结点的分裂属性ID  
        self.childs = {} # 该结点的子树列表,key-value pair: (属性attr的值, 对应的子树)  
        self.parent = parent # 该结点的父亲结点  
          
  
  
def entropy(props):  
    if (not isinstance(props, (tuple, list))):  
        return None  
      
    from math import log  
    log2 = lambda x:log(x)/log(2) # 计算经验熵
    e = 0.0  
    for p in props:  
        e -= p * log2(p)  
    return e  
  
  
def info_gain(D, A, T = -1, return_ratio = False):  
    '''''特征A对训练数据集D的信息增益 g(D,A) 
     
    g(D,A)=entropy(D) - entropy(D|A) 
            假设数据集D的每个元组的最后一个特征为类标签 
    T为目标属性的ID,-1表示元组的最后一个元素为目标'''  
    if (not isinstance(D, (set, list))):  
        return None  
    if (not type(A) is int):  
        return None  
    C = {} # 结果计数字典  
    DA = {} # 属性A的取值计数字典  
    CDA = {} # 结果和属性A的不同组合的取值计数字典  
    for t in D:  
        C[t[T]] = C.get(t[T], 0) + 1  #统计目标属性各种取值下的个数,用户经验熵的计算
        DA[t[A]] = DA.get(t[A], 0) + 1  #统计属性列下各种取值的个数,用于计算经验条件熵
        CDA[(t[T], t[A])] = CDA.get((t[T], t[A]), 0) + 1  #统计(属性列,目标列)下各种组合取值的个数,例如(女,合格)(男、合格)()
      
    PC = map(lambda x : x / len(D), C.values()) # 类别的概率列表
    entropy_D = entropy(tuple(PC)) # map返回的对象类型为map,需要强制类型转换为元组  
  
  
    PCDA = {} # 特征A的每个取值给定的条件下各个类别的概率(条件概率)  
    for key, value in CDA.items():  
        a = key[1] # 特征A的取值
        pca = value / DA[a]  
        PCDA.setdefault(a, []).append(pca)  
      
    condition_entropy = 0.0  
    for a, v in DA.items():  
        p = v / len(D)  
        e = entropy(PCDA[a])  
        condition_entropy += e * p  #计算经验条件熵
      
    if (return_ratio):  
        return (entropy_D - condition_entropy) / entropy_D  #C4.5的信息增益比
    else:  
        return entropy_D - condition_entropy  #ID3的信息增益
      
def get_result(D, T = -1):  
    '''''获取数据集D中实例数最大的目标特征T的值'''  
    if (not isinstance(D, (set, list))):  
        return None  
    if (not type(T) is int):  
        return None  
    count = {}  
    for t in D:  
        count[t[T]] = count.get(t[T], 0) + 1  
    max_count = 0  
    for key, value in count.items():  
        if (value > max_count):  
            max_count = value  
            result = key  
    return result   
  
  
def devide_set(D, A):  
    '''''根据特征A的值把数据集D分裂为多个子集'''  
    #判断D的数据类型是set和list类型
    if (not isinstance(D, (set, list))):  
        return None
    #判断A的数据类型是否是int型
    if (not type(A) is int):  
        return None  
    subset = {}
    '''''根据特征A的结果划分数据集'''
    for t in D:
        subset.setdefault(t[A], []).append(t)  
    return subset
  
  
def build_tree(D, A, threshold = 0.0001, T = -1, Tree = None, algo = "C4.5"):  
    '''''根据数据集D和特征集A构建决策树. 
     
    T为目标属性在元组中的索引 . 目前支持ID3和C4.5两种算法''' 
    #判断Tree是否存在和Tree是否是节点
    if (Tree != None and not isinstance(Tree, Node)):  
        return None
    #判断数据集D的类型是否是set集合和list集合的一种,如果不是直接返回
    if (not isinstance(D, (set, list))):  
        return None
    #判断特征集A的类型是否是一个set集合
    if (not type(A) is set):  
        return None  
      
    if (None == Tree):  
        Tree = Node(None, D)  
    subset = devide_set(D, T)   #根据特征T的取值拆分数据集  
    if (len(subset) <= 1):  #如果该特征T的取值为一个时,则这个唯一取值为这个节点的结果
        for key in subset.keys():  
            Tree.result = key  
        del(subset)  
        return Tree  
    if (len(A) <= 0):  #当特征个数小于等于0的时候,返回
        Tree.result = get_result(D)  
        return Tree  
    use_gain_ratio = False if algo == "ID3" else True  #是要实现ID3还是C4.5算法,如果是ID3算法,use_gain_ratio为false,否则为true
    max_gain = 0.0  
    for a in A:  
        gain = info_gain(D, a, return_ratio = use_gain_ratio)  
        if (gain > max_gain):  
            max_gain = gain  
            attr_id = a # 获取信息增益最大的特征  
    if (max_gain < threshold):  #判断信息增益比是否小于阈值,如果小于,返回数据集D中实例数最大的目标特征T的值
        Tree.result = get_result(D)  
        return Tree  
    Tree.attr = attr_id
    
    subD = devide_set(D, attr_id)  
    del(D[:]) # 删除中间数据,释放内存  
    Tree.dataset = None  
    A.discard(attr_id) # 从特征集中排查已经使用过的特征  
    for key in subD.keys():  
        tree = Node(Tree, subD.get(key))  
        Tree.childs[key] = tree  
        build_tree(subD.get(key), A, threshold, T, tree)  
    return Tree  
  
  
def print_brance(brance, target):  #输出结果
    odd = 0   
    for e in brance:          
        print(e, end = ('=' if odd == 0 else '∧'))  
        odd = 1 - odd  
    print("target =", target)  
  
  
def print_tree(Tree, stack = []):   
    if (None == Tree):  
        return  
    if (None != Tree.result):  
        print_brance(stack, Tree.result)  
        return
    stack.append(Tree.attr)  
    for key, value in Tree.childs.items():  
        stack.append(key)
        print_tree(value, stack)  
        stack.pop()  
    stack.pop()  

# =============================================================================
# #根据决策树产生数据结果   
# def classify(Tree, instance):  
#     if (None == Tree):  
#         return None  
#     if (None != Tree.result):  
#         return Tree.result  
#     return classify(Tree.childs[instance[Tree.attr]], instance)
# =============================================================================

#导入操作excel文件的xlrd库     
import xlrd
#读取文件
bk = xlrd.open_workbook("C:\\Users\\lenovo\\Desktop\\decisiontree_data.xls")
try:
    sh = bk.sheet_by_name("Sheet1")#假设数据在该文件的sheet1下,读取sheet1
except:
    print("当前文件不存在Sheet1")#如果不存在sheet1,则输出当前文件不存在sheet1
rowNum = sh.nrows #读取改文件sheet1下数据的行数
dataset = [] #定义存储数据的列表dataset
#按行循环读取数据
for i in range(1,rowNum):
    rowData = sh.row_values(i)
    dataset.append(rowData)
#开始建立决策树
T = build_tree(dataset, set(range(0, len(dataset[0]) - 1)))
#打印输出决策树
print_tree(T)
# =============================================================================
# #根据决策树产生结果
# print(classify(T, ('女', '好', '每周大于三小时', 'A', 'C', 'B', 'D', 'D')))
# =============================================================================

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/sheziqiong/article/details/127141025
今日推荐