Coursera Mooc数据分析
慕课(Massive Online Open Class,MOOC)自2011年10月在斯坦福大学开展以来,迅速发展并不断改变着传统教学方式。Coursera 作为世界上最大的在线学习平台之一,于 2012 年由斯坦福大学的两位计算机科学教授 Andrew Ng(吴恩达)和Daphne Koller 创办。
由于吴恩达是机器学习领域的专家,该网站在提供在线课程的同时更是详细记录了每个学习者的动作行为,包括学习者的课程学习进度、参与讨论情况、测试或考试成绩等重要数据,尤其是学习者的每次点击、观看视频时间与次数、中途停顿时间点,测试时间与提交次数等学习过程数据,这些数据是对其学习过程的全面记录与客观反映。
通过分析大量学习中产生海量学习数据,可以更好的理解人类“学习”这件事情,并可以有效的促进学习和教育的发展。
1. Coursera的数据结构
Coursera的数据库主要包含Course Information(课程信息)、Course Content(课程内容)、Course Progress(课程进度)、Assessments(评估)、Course Grades(课程成绩)、Discussions(论坛)、Feedback(课程反馈)、Learner(学习者)、Demographics(人口统计)9类100余张表。
1. 1 Course Information(课程信息)
Coursera上的大多数课程都是以学期(session)的形式提供,每个课程学习的学期包含开始日期和结束日期。同一学期的学习者要在每周截止日期前完成相应的课程内容。学期按固定的节奏来安排(如,每个月开始一个新的学期)。
关键表包括course(课程概况)、course_branches(已创建的课程版本)、on_demand_sessions(课程课时的详细信息)
on_demand_session_memberships(学习者注册课时的详细信息)
1. 2 Course Content(课程内容)
教学者创建课程内容(比如模块、课时、讲座和测试等)时,将会形成课程内容的相关数据。每门课的初始课程版本被标记为原始版本,任何时候教学者都可使用课程版本特征来创建额外的课程版本,称为分支(branch)。
每个课程版本包括三个等级结构:模块(modules)、课时(lessons)和项目(items),每个模块(每一讲)包含若干课时,每个课时有多个项目,比如视频、测试等。
关键表包括course_branch_modules(模块表)、course_branch_lessons(课时表)、course_branch_items(项目表)
1.3 Course Progress(课程进度)
course_progress是记录学习者行为的关键表,学习者与课程中的项目每互动一次就会在表course_progress中记录一行数据。每一行数据都会记下用户和课程项互动时间以及学习项目**“已开始”或“已完成”**的进度状态。
其中,对于课时视频项目而言,指习者在浏览器中查看视频项目,播放视频的头几秒钟即为“已开始”学习该视频项目,播放视频的最后几秒钟即为“已完成”该视频项目。
对于测试课时项目而言,开始测试或提交不及格的小测验记录为“已开始”。提交测试通过记录为“已完成”的测试项目。如果学习者在第一次尝试中通过了完成,那么就没有“开始”的记录,因为学习者直接进入了“已完成”状态。
1.4 Assessments(评估)
关键表如下
-
course_branch_item_assessments包含
course_item_id
与assessment_id
的对应关系。其中assessment_id
标识课时习题。 -
assessments包含每个
assessment_id
由assessment_base_id
与assessment_version
组成(习题有多个版本),以及每个assessment的类型。 -
assessment_assessments_questions包含每个
assessment_id
下对应的assessment_question_id,order(顺序)以及weight(分数) -
assessment_questions包含每个question的题目信息。
-
assessment_options包含每个question的答案信息。
-
assessment_actions包含每个学习者对于每个assessment的时间记录
1.5 Course Grades(课程成绩)
关键表如下
- course_grade包含学习者课程中所取得的最高成绩以及是否通过了该课程。
- course_branch_grade包含在给定的某一课程版本中,学习者课程中所取得的最高成绩以及是否通过了该课程。
- course_item_grade包含学习者在课程中每个项目的成绩,即每门课程必修内容的最新成绩。
- course_formative_quiz_grades包含课程完成的非必修科目成绩。只是没有表示通过状态的列,因为形成性测试不是课程完成的必修课。
1.6. Discussions(论坛)
关键表如下
- discussion_course_forums:列出了不同论坛(如”一般讨论,”“见面打招呼,”等)及其所在的课程。
- discussion_questions:包括在每个线程原来的帖子,作者和线程在课程中所处的位置。
- discussion_answers:列出了对前一个表格问题的回复。
其他论坛相关表格是关于论坛关注度、投票和(对问题或答案的)标记:
- discussion_answer_flags和 discussion_questions_flags:对攻击性回复标记或攻击性问题标记的记录,学习者可以标记一个答案或问题让Coursera社区运营团队审核,该答案或问题是否符合社区指南(如是否具有攻击性或为垃圾邮件)。
- discussion_answer_votes记录了一个答案被学习者投票或撤销投票的信息。
- discussion_questions_votes记录讨论问题的投票结果。
- discussion_questions_followings: 记录讨论问题被关注或取消关注的时间。
1.7 Feedback(课程反馈)
学习者是否喜欢课程内容或对课程的评分将记录在课程反馈表中,关键表如下:
- feedback_course_ratings包含两组不同的课程评分,可以根据feedback_system列进行区分。”星”的价值在于整个课程的五星评分体系。截至2016年春季,Coursera正在进行一项名为”网络推广者得分”(NPS)的测试,以更好地了解学习者对课程的总体满意度。在feedback_system列中,NPS结果的新值是”NPS_FIRST_WEEK”和”NPS_END_OF_COURSE”。
- feedback_item_ratings包含课程项目的”喜欢”或”不喜欢”评级。虽然学习者可以对相同的课程(项目)进行多次评分,但导出中提供的数据经过筛选,仅为每对学习者-课程(学习者-项目)提供最新的评分。
- feedback_course_comments在star和NPS反馈系统中,包含了学习者对课程的评论,feedback_item_comments包含来自标记课程内容的学习者的评论。记录自由文本的响应,包含了对课程的整个评论历史,而不仅仅是最近的评论
1.8 Learner(学习者)
关键表如下:
-
users:根据Coursera的数据共享政策和研究政策,不包括用户名和电子邮件等个人身份信息(PII),主要包含以下字段:
- 地理列由Maxmind地理定位服务推断用户的浏览器IP填充。
- 语言列由用户的配置文件设置或用户浏览器中的值填充。
- reportted_or_inferred_gender列包含”male”、”female”或NULL值。
- employment_status列的值对应于学习者在Coursera配置文件中对就业状况问题的选择。
- educational_achievement列的值对应于学习者在Coursera配置文件中对教育成就问题的选择。
- student_status列的值对应于学习者在Coursera配置文件中对学生状态问题的选择。
-
course_membership:Coursera用户被分配到课程中的一个成员角色时,就会记录下来。常见值如下:
- “LEARNER”: “学习者”:点击已启动课程的注册按钮的用户
- “PRE_ENROLLED_LEARNER”:用户预注册课程或系列
- “NOT_ENROLLED”:用户由于某系些理由没用注册
- “MENTOR”: 被邀请并接受对课程讨论进行调节的用户
- “BROWSER”: “浏览者”:用户预览课程描述页面上的内容,但并没有点击注册按钮”INSTRUCTOR”: “导师”:用户曾经设置为课程的讲师
随着时间的推移,一个学习者可能在一门课程中扮演多个角色。在这种情况下,学习者将在表中有多个记录。例如,学习者可以查看预览内容(“BROWSER”),然后点击注册按钮加入(“learner”),几天后退出(“not_registration”)。
此表只包含曾经达到”学习者”、”导师”或”讲师”角色的用户的成员信息。例如,它不包含任何只包含预览课程材料但从未完成注册过程的”浏览器”用户。
1.9 Demographics(人口统计)
人口统计相关表格主要来自学习者参加Coursera的自愿调查,关键表如下:
- demographics_questions自愿调查问题表:完整的问题列表包含在demographics_questions表中。
- demographics_answer自愿调查回答表:包含来自Coursera学习者的答案。
Coursera课程的用户行为数据是从postgre数据库中导出,均为.csv文件,可通过在本地Postgre执行提供的setup.sql建立表,然后使用load.sql加载csv数据文件。
psql -e -U postgres -d postgres -f load.sql
更为详细的表结构和字段信息可以查看Coursera提供的Data Exports Guide。
2. 学习者行为分析
本文基于Coursera平台上的某慕课后台数据,围绕学习者观看视频和提交测试两类关键行为,对学习者行为进行分析。
该慕课共12讲,每一讲包含若干课时,共66个课时,包括64个教学课时以及期中、期末考试各1个课时。每个教学课时主要由教学视频、测试以及论坛三部分组成。教学视频时长在5-14分钟不等,测试题目在5-12个不等,包括选择、填空、判断等多种类型。
学习者在注册慕课后,主要通过观看视频、进行测试和参加讨论三类行为来来开展学习。该课程共有2130人注册,在课程学期开始后实际参与学习的,即有观看视频或进行测试行为(该课程不涉及问题讨论)的人数为1777人。对慕课每课时参与学习的人数进行统计,如图所示:
可以看出课程参与人数在课程前两课时迅速递减,随后相对趋于平缓。其中前三课时的参与人数分别为1628、899、674,第一讲课时1与课时2的课程参与人数流失率高达44.78%与25.03%,随后人数变化趋于平缓,最终完成课程学习并通过测试和考试的共有34人,完成率为1.6%。
但是由于慕课学习者具有不同于传统课堂学习者的特点,将完成课程测试作为衡量学习效果的唯一标准有失偏颇,比如有的参与者仅仅观看部分视频学习部分知识点,并不以完成课程为最终目标;而部分完成课程的参与者并未完全看完所有视频,但却完成了所有测试。
为了深入研究学习者行为,本研究提取“完成视频数”、“完成测试数”和“课程得分”三个特征,使用K-means算法对该慕课学习者进行聚类分析。
2.1 加载文件
主要用到course_branch_items
、course_progress
、 course_grades
数据表,代码如下:
import pandas as pd
filePath = r'/Users/pl/Tutorial/HanyuYufa/hanyu_yufa_data/data'
items = pd.read_csv(filePath+r'/2.3course_branch_items.csv')
progress = pd.read_csv(filePath + r'/3.1course_progress.csv')
user_grades =pd.read_csv(filePath+r'/5.1course_grades.csv')
2.2 特征工程
- 视频完成数:通过抽取
course_progress
表中学习者完成(course_progress_state_type_id==2)项目为视频的数据,统计后得出。 - 完成测试数:通过抽取
course_grades
中的course_grade_verified_passed_items字段得出。 - 课程得分 :通过抽取
course_grades
中的course_grade_verified字段得出。
代码如下:
user_item_comp =progress[progress.course_progress_state_type_id==2]\
[['pku_user_id','course_item_id']].drop_duplicates() #完成项目
itemsV_id = items[items.course_item_type_id==1].course_item_id #课程项目 (视频)id
user_itemV_comp = pd.DataFrame(itemsV_id).merge(user_item_comp) #完成项目(视 频)
user_compV_cou = user_itemV_comp.pku_user_id.value_counts()
user_compV_cou.name = 'user_compV_cou'
user_compV_cou.index.name = 'pku_user_id'
# 拼接形成用户特征矩阵
user_matirx =pd.merge(pd.DataFrame(user_compV_cou),\
user_grades[['pku_user_id','course_grade_verified_passed_items','course_grade_verified']],\
how='outer',right_on = 'pku_user_id',left_index=True)
user_train= user_matirx.fillna(0)[['user_compV_cou', 'course_grade_verified_passed_items','course_grade_verified']]
形成的用户行为特征矩阵如下表所示:
用户ID | 完成视频数 | 完成测试数 | 课程得分 |
---|---|---|---|
ce10169a0b58f90a60c7c8518c466a873523 | 7 | 66 | 92.07 |
08d1d10834a0f91f69c60c2f479ee568272a | 64 | 30 | 29.33 |
670c6f2f81ced2c26e8d1ace1e4586a9b6e2 | 10 | 6 | 5.67 |
… | … | … | … |
6b6abfd44ce30c7004aea7ced8342792f03a | 1 | 1 | 0.83 |
其中完成视频数为区间 [ 1 , 64 ] [1, 64] [1,64]上的值,完成测试数为区间 [ 1 , 66 ] [1, 66] [1,66]上的值,课程得分根据每一课时的测试、期中、期末测试得分及权重计算,为区间 [ 0 , 100 ] [0, 100] [0,100]上的值。
2.3 模型训练
使用K-Means聚类算法,根据学习中的行为特征,对其进行聚类分析。聚类分析作为一种无监督学习的机器学习方法,可以根据数据对象之间的相似程度大小,将其自动划分成多个簇,使得簇中的对象彼此相似,但与其他簇中的对象尽可能不相似。利用聚类分析结果,根据生成的每个结果类群的特征性质,能够针对特定群体展开更为深入的分析。
代码如下:
kmodel = KMeans(n_clusters = 5,n_init=10000, max_iter=50000, n_jobs = 4) #n_jobs是并行数,一般等于CPU数较好
kmodel.fit(user_train) #训练模型
2.4 结果分析
(1)聚类分析
经过训练后,聚类算法自动将包含1777名学习者行为特征的数据集 划分到
k
=
5
k=5
k=5个簇中。可使用Matplotlib中的三维图的工具包mpl_toolkits.mplot3d
对数据进行可视化。如图所示,其中X轴为观看视频数,Y轴为完成测试数,Z轴为课程得分。
根据学习者的分类特征定义为真正学习者、高分测试者、视频学习者、中途退出者、注册体验者:
-
真正学习者:指既观看课程视频,又完成相应测试的学习者。这类学习者有50人,占比3%,其中有19人通过了课程,通过率为38%。他们视频和测试的平均完成个数分别高达57和58.2,完成率分别为89%和88%,课程平均得分为75.63分,虽然相比“高分测试者”略低,但他们不仅注重完成测试,还注重观看视频,比较符合边学边测的特征,是真正的慕课学习者。
-
高分测试者:指很少观看课程视频,但完成了绝大多数测试的学习者。这样的学习者有24人,占比只有1.4%,但其课程通过率和课程平均得分都是所有类型学习者中最高的,分别为63%和92.07分。他们视频平均完成率比较低,只有20%,但测试平均完成率非常高,为96%。这类学习者的学习目的很可能主要是获得课程证书认证或者利用慕课来检测自己线下学习的效果,甚至不排除某些代上课行为。
-
视频学习者:指较多观看课时视频,较少参加课时测试的学习者。这部分学习者共有16人,占比1%。平均完成视频数57.1个,视频完成率高达89%,而测试完成率只有16%,课程平均得分为10.84分。
-
中途退出者:指学习者边看视频边做测试,但之后陆续退出了课程学习。这类学习者总计159人,占比9%。其视频和平均完成数量约为19个,二者完成率均为30%,课程得分平均分为19.48分。如图13所示,大部分学习者(紫色)在完成模块四的学习之后,逐渐退出了课程学习。
-
注册体验者:指视频和测试参与度均较低的学习者。如表4所示,注册体验者共计1528人,占比84%。其中有751人未完成任何一个视频与测试,比如有人只是观看视频几秒钟或只做了一个测试题,还有有777人至少完成了一个及一个以上的视频或测试,但其视频或测试平均完成数目只有2个左右,平均完成率分别为4%、3%。
result = pd.concat([user_matirx,pd.Series(kmodel.labels_,index = user_matirx.index)],axis=1)
result.columns = list(user_matirx.columns) + [u'聚类类别']
pd.Series(kmodel.labels_).value_counts()
from mpl_toolkits.mplot3d import Axes3D
x0,x1,x2,x3,x4 = result[result.聚类类别==0].user_compV_cou,\
result[result.聚类类别==1].user_compV_cou,\
result[result.聚类类别==2].user_compV_cou,\
result[result.聚类类别==3].user_compV_cou,\
result[result.聚类类别==4].user_compV_cou
y0,y1,y2,y3,y4 = result[result.聚类类别==0].course_grade_verified_passed_items,\
result[result.聚类类别==1].course_grade_verified_passed_items,\
result[result.聚类类别==2].course_grade_verified_passed_items,\
result[result.聚类类别==3].course_grade_verified_passed_items,\
result[result.聚类类别==4].course_grade_verified_passed_items
z0,z1,z2,z3,z4 = result[result.聚类类别==0].course_grade_verified*100,\
result[result.聚类类别==1].course_grade_verified*100,\
result[result.聚类类别==2].course_grade_verified*100,\
result[result.聚类类别==3].course_grade_verified*100,\
result[result.聚类类别==4].course_grade_verified*100
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x2, y2, z2, c='g', label='真正学习者') ##54 绿 2
ax.scatter(x3, y3, z3, c='y', label='高分测试者') ##24 黄 1
ax.scatter(x4, y4, z4, c='b', label='视频学习者') ##12 蓝 4
ax.scatter(x0, y0, z0, c='k', label='中途退出者') ##99 黑 3
ax.scatter(x1, y1, z1, c='r', label='注册体验者') ##837 红 0
ax.legend(loc='best')
# 添加坐标轴(顺序是Z, Y, X)
ax.set_zlabel('Z', fontdict={'size': 15, 'color': 'black'})
ax.set_ylabel('Y', fontdict={'size': 15, 'color': 'black'})
ax.set_xlabel('X', fontdict={'size': 15, 'color': 'black'})
plt.show()
(2)分类流失模型
对不同类别慕课学习人数流失率进行分析发现,学习人数减少幅度最大的是“注册体验者”,注册体验者共计1498人,占比84%。除去未完成任何视频与测试的751人,还有777人其视频或测试平均完成数目仅有2个左右,这说明学习者在稍作体验后便放弃了课程学习。
此外,所占比例较多的是“中途退出者”,占比9%,这类学习者在前四个模块观看视频和完成测试的数量相当,可见是比较认真学习的,但大约在课程学习进行到一半及之后逐渐退出了课程学习。
user_module_type = result.merge(user_module,how='left',on='pku_user_id')
cou = pd.crosstab(user_module_type.course_module_id,user_module_type.聚类类别)
cou.columns.name = '学习者类别'
cou = cou.reindex(labels=[1,0,4,3,2],axis="columns")
cou = cou.reindex(index = modules.sort_values(by='course_branch_module_order')['course_module_id'])
module_dict = dict((modules.loc[i].course_module_id, modules.loc[i].course_branch_module_name[:4]) for i in modules.index)
cou.columns =['注册体验者','中途退出者','视频学习者','高分测试者','真正学习者']
cou.rename({'A0BA4':'第四讲'},inplace=True)
cou.rename(module_dict,inplace=True)
cou.index.name = '课程名称'
cou.plot(kind='bar',stacked=True)
因此,教学团队要完善和丰富课程设计及教学内容,提升MOOC的教学水平,应首先从课程第一讲开始,尤其要在第一讲的前两个课时上下功夫。“良好的开始是成功的一半”,只有在课程开始部分增强学习者对课程的良好体验,才有可能留住更多“注册体验者”,让其成为“真正学习者”。
3. 知识点难度分析
学习者通过观看视频与参加测试来完成每一课时的学习,慕课后台数据记录了名学习者观看视频与参加测试的行为数据。学习者在观看视频过程中会由于知识点较难而出现多次暂停,甚至未能完成观看的情况。因此通过对学习者学习行为的分析,可以看出不同知识点的难度不同,一般较为简单的知识点,学习者在观看视频过程中很少有停顿,反之对于较难的知识点,会多次停顿,或者多次观看视频。
经对64个课时视频观看数据分析,54.5%的人一次性完成视频观看(即未存在暂停),而有43.4%的人需要暂停2-5次才能完成视频观看;对于较难的课时,学习者也会存在无法完成测试,或者测试成绩较低的情况。
经过梳理,该慕课的64个课时共覆盖25个知识点,
3.1 特征工程
基于学习者观看视频和参加测试的行为数据,选取视频观看完成比、视频观看完成比、测试完成比、测试完成比四个特征,构建特征矩阵 ( 64 × 4 ) (64 \times 4) (64×4),其中:
视频观看完成比 = 视频完成人数 / 视频观看人数 视频观看完成比 = 视频完成人数/视频观看人数 视频观看完成比=视频完成人数/视频观看人数 视频观看完成比 = 视频一次性完成人数 / 视频完成人数 视频观看完成比 = 视频一次性完成人数/视频完成人数 视频观看完成比=视频一次性完成人数/视频完成人数 测试完成比 = 测试完成人数 / 参加测试人数 测试完成比 = 测试完成人数/参加测试人数 测试完成比=测试完成人数/参加测试人数 测试完成比 = 测试总得分 / 测试完成人数 测试完成比 = 测试总得分/测试完成人数 测试完成比=测试总得分/测试完成人数
如针对第一讲的7个课时,特征矩阵如下所示:
课时名称 | 视频观看完成比 | 视频一次性完成比 | 测试完成比 | 测试平均得分 |
---|---|---|---|---|
课时1 | 0.4656 | 0.5343 | 0.7256 | 0.8099 |
课时2 | 0.4839 | 0.4506 | 0.7018 | 0.8665 |
课时3 | 0.5148 | 0.4669 | 0.6893 | 0.9473 |
课时4 | 0.5074 | 0.5227 | 0.6331 | 0.9229 |
课时5 | 0.4578 | 0.4549 | 0.6280 | 0.8926 |
课时6 | 0.4542 | 0.4538 | 0.6009 | 0.9183 |
课时7 | 0.4573 | 0.6174 | 0.5829 | 0.9120 |
Step2:对每个特征值使用 z z z~ s c o r e score score进行规范化处理,特征 A A A的值 v i v_i vi被规范化为: v i ′ = v i − A ˉ σ A v{_i}^{'} = \frac{v_i - \bar{A}}{\sigma_{A}} vi′=σAvi−Aˉ其中, A ˉ \bar{A} Aˉ和 σ A \sigma_{A} σA分别为属性A的均值和方差。
Step3:针对每一课时的特征进行线性加和,得到每一课时的难度值 D L i ( i = 1 , 2 , . . . , 64 ) D_{L_i}(i=1,2,...,64) DLi(i=1,2,...,64)。
Step4:定义知识点难度指数为其所涉及课时的难度的汇总平均,即 D G k = ∑ j = 1 n D L _ j n ( k = 1 , 2 , . . . , 25 ) D_{G_k}= \frac{\sum\limits_{j=1}^{n}{D_{L\_j}}}{n}(k=1,2,...,25) DGk=nj=1∑nDL_j(k=1,2,...,25)其中, n n n为该知识点所涉及的课时数, D L _ j D_{L\_j} DL_j为课时j的难度值。
最后,通过最大-最小规范化,将到每个知识点的难度指数映射到区间 [ 1 , 10 ] [1,10] [1,10]之间的值。
3.2 结果分析
根据难度指数,我们回看慕课视频及PPT展示内容发现,学习者观看视频回放次数多或花费时间长的地方,是由于课程内容的信息量过大。如“第三讲的课时5”视频时长为11分钟,而“第十一讲课时2”的视频时长为12分钟,虽然视频时长只比第三讲的课时5多了一分钟,但其视频平均观看时长(29.09分钟)却是第三讲的课时5(16.93分钟)的近两倍。
对此,我们仔细研究课程视频内容发现,“第十一讲课时2:”的PPT课件展示文字比较密集,展示密度比较大,12分钟的视频课程里要展示32张PPT,导致学习者应接不暇。建议可以将这类拆分成两个课时视频讲解,减少每个课时视频展示PPT的数量,以便学习者理解。
import numpy as np
from datetime import timedelta
modules = pd.read_csv(filePath+r'/course_branch_modules.csv')
lessons = pd.read_csv(filePath+r'/course_branch_lessons.csv')
items = pd.read_csv(filePath+r'/course_branch_items.csv')
data = items.merge(lessons,how='left',on='course_lesson_id').merge(modules,how='left',on='course_module_id')
col_idname = ['course_module_id','course_lesson_id','course_item_id',
'course_branch_module_name','course_branch_lesson_name','course_branch_item_name']
col_order = ['course_branch_module_order','course_branch_lesson_order','course_branch_item_order']
data_sort = data.sort_values(by=col_order)
data_sort.index = np.arange(1,131)
progress = pd.read_csv(filePath + r'/course_progress.csv')
user_item = progress[['pku_user_id','course_item_id']].drop_duplicates()
#每个item参与人数
item_cou = user_item.course_item_id.value_counts()
item_cou.name = 'item_cou'
item_cou.index.name = 'course_item_id'
item_merge = pd.DataFrame(item_cou).merge(data_sort,right_on='course_item_id',left_index=True) #需要module和lesson的order
item_cou = item_merge.sort_index()[['course_branch_item_name','item_cou']]
user_item_comp =progress[progress.course_progress_state_type_id==2]\
[['pku_user_id','course_item_id']].drop_duplicates() #完成项目
#Feature1 视频观看完成比=视频完成人数/视频观看人数 itemV_pct=itemV_comp_cou/itemV_cou
itemsV_id = items[items.course_item_type_id==1].course_item_id #课程项目 (视频)id
user_itemV_comp = pd.DataFrame(itemsV_id).merge(user_item_comp) #完成项目(视 频)
itemV_comp_cou = user_itemV_comp.course_item_id.value_counts() #每个视频的完成人数
itemV_comp_cou.name = 'itemV_comp_cou'
itemV_comp_cou.index.name = 'course_item_id'
itemV_comp_merge = pd.DataFrame(itemV_comp_cou).merge(data_sort,right_on ='course_item_id',left_index=True)
itemV_comp_cou = itemV_comp_merge.sort_index()[['course_branch_item_name','itemV_comp_cou']] #视频完成人数
itemV_cou = item_cou.loc[itemV_comp_cou.index] #视频观看人数
itemV_pct = itemV_comp_cou.itemV_comp_cou/itemV_cou.item_cou #视频观看完成比
#Feature2 视频一次性完成比=视频一次性完成人数/视频完成人数#视频一次性完成人数
#itemV_one_pct = itemV_comp_one/itemV_comp_cou
progress['ts'] =pd.to_datetime(progress.course_progress_ts)
df=pd.DataFrame(columns=['course_item_id', 'pku_user_id', 'tcou'])
for course_item in itemsV_id:
df_slice = progress[(progress.course_item_id == course_item)]
user_slice = df_slice[df_slice.course_progress_state_type_id==2].pku_user_id.unique()
for user in user_slice:
df_slice_out =df_slice[(df_slice.pku_user_id==user)].sort_values(by='ts')
if (len(df_slice_out)>1):
ts_len = len(df_slice_out.ts)
tcou = 1
for i in range(1,ts_len):
tmp = df_slice_out.ts.iloc[i]-df_slice_out.ts.iloc[i-1]#计算每次时间间隔
if tmp > timedelta(0.02): #大于半小时增加1次观看次数
tcou +=1
df = df.append({'course_item_id':course_item,'pku_user_id':user,'tcou':tcou},ignore_index=True)
itemV_comp_one = df[df.tcou==1].course_item_id.value_counts() #视频一次性完成人数
itemV_comp_one.name = 'itemV_one_cou'
itemV_comp_one.index.name = 'course_item_id'
itemV_comp_merge = pd.DataFrame(itemV_comp_one).merge(data_sort,right_on ='course_item_id',left_index=True)
itemV_comp_one = itemV_comp_merge.sort_index()[['course_branch_item_name','itemV_one_cou']]#视频一次性完成人数
itemV_one_pct = itemV_comp_one.itemV_one_cou/itemV_comp_cou.itemV_comp_cou #视频一次性完成比
#Feature3 测试完成比 = 测试完成人数/参加测试人数
itemA_index = list(np.arange(2,69,2))+list(np.arange(71,130,2))
itemA_cou = item_cou.loc[itemA_index]
itemA_id = data_sort.loc[itemA_index].course_item_id
user_itemA_comp = pd.DataFrame(itemA_id).merge(user_item_comp) #完成项目(视频)
itemA_comp_cou = user_itemA_comp.course_item_id.value_counts() #每个视频的完成人数
itemA_comp_cou.name = 'itemA_comp_cou'
itemA_comp_cou.indexname='course_item_id'
itemA_comp_merge = pd.DataFrame(itemA_comp_cou).merge(data_sort,right_on ='course_item_id',left_index=True)
itemA_comp_cou = itemA_comp_merge.sort_index()[['course_branch_item_name', 'itemA_comp_cou']]
itemA_pct = itemA_comp_cou.itemA_comp_cou/itemA_cou.item_cou
#Feature4 测试平均得分 = 测试总得分/测试完成人数
item_grades =pd.read_csv(filePath+r'/course_item_grades.csv')
item_grades_mean = item_grades.pivot_table(values = 'course_item_grade_overall',index='course_item_id',aggfunc='mean')
item_grades_merge = pd.DataFrame(item_grades_mean).merge(data_sort,right_on = 'course_item_id',left_index=True)
item_grades_mean = item_grades_merge.sort_index()['course_item_grade_overall']
item_grades_mean = item_grades_mean.loc[itemA_index].rename(columns={'course_item_grade_overall': 'mean'}) #重命名
diff_matrix = pd.concat([pd.Series(itemV_pct.values),pd.Series(itemV_one_pct.values),
pd.Series(itemA_pct.values),pd.Series(item_grades_mean.values)],
ignore_index=True,axis=1)
from sklearn.preprocessing import StandardScaler
yf = pd.read_excel(r'/Users/pl/Tutorial/mooc csdn/hanyu_yufa_data/data.xlsx')
scaler = StandardScaler().fit_transform(1-diff_matrix)
diff_matrix_sca = pd.DataFrame(scaler)
diff_matrix_sca['dvalue'] = diff_matrix_sca.sum(axis=1)
diff_yfv = pd.concat([yf.语法点,diff_matrix_sca['dvalue']],axis=1)
diff_yf = diff_yfv.groupby('语法点').mean()
diff_out = (diff_yf - diff_yf.min())/(diff_yf.max() - diff_yf.min())*9+1