教育知识图谱
教育知识图谱
背景
为了解决教师在教学过程中知识框架梳理、组卷策略等问题, 以及学生在学习过程中认知过载、学习迷航等问题,知识图谱被引入教育行业。针对这些需求,本文以高中数学学科知识图谱为例,提供了教育图谱在知识导航、组卷策略等方面的应用示例。
数据建模
首先我们需要构建教育图谱的图数据模型。图数据模型中的实体包括知识点和题目,实体关系包括知识点之间的包含关系以及知识点和题目之间的关联关系,具体的图模型见下图:
图模型中包含了两类点和两类边,元信息说明如下:
数据集
本文采集了高中数学几乎所有的知识点和部分题目信息,根据设计的图模型对数据格式进行转换,转换后的数据可从此处下载。这份数据包含7W+个点,14W+条边。
创图
本文将使用华为云图数据库 GES 对以上数据集进行探索和演示,我们需要先在 GES 中创图并将以上数据集导入,详细指导流程可参见华为云图引擎服务 GES 实战——创图。
使用 GES 查询的预置条件
下面文件封装了使用 GES 查询的预置条件,包括配置相关参数和对所调用 API 接口的封装。
import moxing as mox
mox.file.copy('obs://obs-aigallery-zc/GES/edu_knowledge_graph/config.py', 'config.py')
config类的参数都是与调用 GES 服务有关的参数,依次为“终端节点”、“IAM 用户名”、“IAM 用户密码”、“IAM 用户所属账户名”、“项目名称”、“公网访问地址”、“项目ID”、“token值”,其获取方式可参考调用 GES 服务业务面 API 相关参数的获取。
下面文件封装了与查询相关的接口。
mox.file.copy('obs://obs-aigallery-zc/GES/edu_knowledge_graph/ges_func.py','ges_func.py')
创建好图之后,就可以对其进行查询和分析了。
import time
import json
from config import config
from ges_func import GESFunc
# 需填入参数
iam_url = ''
user_name = ''
password = ''
domain_name = ''
project_name = ''
eip = ''
project_id = ''
graph_name = ''
config = config(iam_url, user_name, password, domain_name, project_name, eip, project_id, graph_name)
ges_util = GESFunc(config.eip, config.project_id, config.graph_name, config.token)
GES 支持 cypher 查询语言,后续的查询示例使用到 cypher 查询语言。在使用 cypher 查询之前,我们先创建点索引和边索引(可直接点击GES画布右下角“创建索引”按钮)。
print('开始创建点索引:')
job_id = ges_util.build_vertex_index()
job_result = ges_util.get_job(job_id)
if 'errorCode' not in job_result:
for i in range(100):
if job_result['status'] == 'success':
break
else:
time.sleep(1)
job_result = ges_util.get_job(job_id)
print('点索引创建完成')
print('开始创建边索引:')
job_id = ges_util.build_edge_index()
job_result = ges_util.get_job(job_id)
if 'errorCode' not in job_result:
for i in range(100):
if job_result['status'] == 'success':
break
else:
time.sleep(1)
job_result = ges_util.get_job(job_id)
print('边索引创建完成')
查询演示
查询这份图数据的统计信息:
print('统计信息:')
result = ges_util.summary()
format_result = json.dumps(result, indent=4)
print(format_result)
统计信息:
{
"vertexNum": 70528,
"labelDetails": {
"labelInVertex": {
"knowledge_point": 2163,
"exercises": 68365
},
"labelInEdge": {
"include": 2145,
"related": 138742
}
},
"edgeNum": 140887
}
可以看到,这份知识图谱包含2000多个知识点和接近七万的题目。
知识点图谱
输入某个知识点,将展示该知识点所有下游知识点。
knowledge_point = '集合的基本运算'
statement = "g.V('{}').repeat(outE().otherV().hasLabel('knowledge_point')).emit().path()".format(knowledge_point)
result = ges_util.gremlin_query(statement)['results']
format_result = json.dumps(result, indent=4, ensure_ascii=False)
# print(format_result)
题目知识点追踪
输入题目,将追踪到该题目考察的所有知识点。
exercises_id = '1'
statement = "g.V('{}').repeat(inE().otherV().hasLabel('knowledge_point')).emit().path()".format(exercises_id)
result = ges_util.gremlin_query(statement)['results']
format_result = json.dumps(result, indent=4, ensure_ascii=False)
# print(format_result)
知识点关系查询
knowledge_point_1 = "集合"
knowledge_point_2 = "空集"
result = ges_util.n_paths(knowledge_point_1, knowledge_point_2)
format_result = json.dumps(result, indent=4, ensure_ascii=False)
# print(format_result)
某知识点包含哪些知识点
knowledge_point = "集合"
statement = "match (n)-->(m:knowledge_point) where id(n) = '{}' return id(m)".format(knowledge_point)
result = ges_util.cypher_query(statement)
format_result = ges_util.format_cypher_result(result)
print(format_result)
id(m)
0 集合的含义与表示
1 集合间的基本关系
2 集合的基本运算
与某知识点相关的题目的数量
knowledge_point = "描述法表示集合"
statement = "match (n)-->(m:exercises) where id(n) = '{}' return count(m)".format(knowledge_point)
result = ges_util.cypher_query(statement)
format_result = ges_util.format_cypher_result(result)
print(format_result)
包含某知识点的题型分布
knowledge_point = "描述法表示集合"
statement = "match (n)-->(m:exercises) where id(n) = '{}' return m.type, count(*)".format(knowledge_point)
result = ges_util.cypher_query(statement)
format_result = ges_util.format_cypher_result(result)
print(format_result)
m.type count(*)
0 解答题 127
1 单选题 277
2 多选题 15
3 填空题 118
4 双空题 13
5 概念填空 4
某知识点会和哪些其他知识点一起考察
knowledge_point = "描述法表示集合"
statement = "match (n)-->(m:exercises)<--(p:knowledge_point) where id(n) = '{}' return id(p), count(*)".format(knowledge_point)
result = ges_util.cypher_query(statement)
format_result = ges_util.format_cypher_result(result)
print(format_result)
自动组卷
为了考察学生的学习情况,老师需要组织一套试卷,该例子中,限制了考察的知识点范围,以及各个题型的题目数量,skip的含义是在所有满足条件的试卷中选择某一套试卷。
knowledge_point = "描述法表示集合"
single_choice_num = 4
multiple_choice_num = 2
gap_filling_num = 2
free_response_question_num = 2
skip = 1
exercises_list = ges_util.test_paper_composition(single_choice_num, multiple_choice_num, gap_filling_num,
free_response_question_num, knowledge_point, skip)
format_result = ges_util.format_cypher_result(exercises_list)
print(format_result)
拿到一份试卷后,我们可以看看这套试卷整体的难易程度,当然也可以将试卷的难易程度作为组织试卷的限制条件。
print('试题的平均通过率(难度):')
ave_pass_rate = ges_util.ave_pass_rate(exercises_list, 10)
print(ave_pass_rate)
- 点赞
- 收藏
- 关注作者
评论(0)