基于在校学习平台MOOC的选课推荐系统

news2024/11/16 19:59:21

基于在校学习平台MOOC的选课推荐系统

1、效果

在线demo,点我查看
在这里插入图片描述

2、功能

根据学生于在校学习平台MOOC学习期间的选课记录等相关特征来对学生进行课程推荐。
采用数据挖掘技术,包括BPR、FM、CF,神经网络推荐,用户协同过滤推荐。
用到的数据集来自于XuetangX,数据集的名称为Course Recommendation,该数据中记录了学生于在线学习平台XuetangX上的选课学习记录,包括学生id、时间、课程id、类别id等。
关于数据集的详细介绍可以参照官方说明。
数据集介绍链接如下:http://moocdata.cn/data/course-recommendation。

登录注册,个人中心,冷启动,热门课程,课程推荐,课程分类,可视化,收藏,选修,点赞,评论,评分

3、推荐算法

3.1 导入库

# -*- coding: utf-8 -*-

"""
@contact: (微)信 1257309054
@file: test.py
@time: 2024/6/22 12:46
@author: LDC
"""
pip install numpy
pip install pandas
pip install tensorflow

3.2 算法说明

1、从数据库中获取所有选修数据
2、对矩阵进行向量化,便于神经网络学习
3、使用LabelEncoder将字符串标签转换为整数标签
4、划分训练集与测试集
5、创建NCF模型
6、合并 embeddings向量
7、添加全连接层
8、编译模型
9、模型训练
10、模型评估
11、模型保存
12、模型推荐

3.3 全部代码

# -*- coding: utf-8 -*-

"""
@contact: 微信 1257309054
@file: recommend_ncf.py
@time: 2024/6/16 22:13
@author: LDC
"""
import os
import django
import joblib
import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from keras.models import load_model

os.environ["DJANGO_SETTINGS_MODULE"] = "course_manager.settings"
django.setup()
from course.models import *


def get_all_data():
    '''
    从数据库中获取所有物品评分数据
    [用户特征(点赞,收藏,评论,
    物品特征(收藏人数,点赞人数,浏览量,评分人数,平均评分)
    ]
    '''
    # 定义字典列表
    user_item_list = []
    # 从评分表中获取所有课程数据
    item_rates = RateCourse.objects.all().values('course_id').distinct()
    # 获取每个用户的评分数据
    for user in User.objects.all():
        user_rate = RateCourse.objects.filter(user=user)
        if not user_rate:
            # 用户如果没有评分过任何一本课程则跳过循环
            continue
        data = {'User': f'user_{user.id}'}
        for br in item_rates:
            item_id = br['course_id']
            ur = user_rate.filter(course_id=item_id)
            if ur:
                data[f'item_{item_id}'] = ur.first().mark  # 对应课程的评分
            else:
                data[f'item_{item_id}'] = np.nan  # 设置成空
        user_item_list.append(data)
    data_pd = pd.DataFrame.from_records(user_item_list)
    print(data_pd)
    return data_pd


def get_data_vector(data):
    '''
    对矩阵进行向量化,便于神经网络学习
    '''
    user_index = data[data.columns[0]]
    data = data.reset_index(drop=True)
    data[data.columns[0]] = data.index.astype('int')
    scaler = 5  # 评分最高为5,把用户的评分归一化到0-1

    df_vector = pd.melt(data, id_vars=[data.columns[0]],
                        ignore_index=True,
                        var_name='item_id',
                        value_name='rate').dropna()
    df_vector.columns = ['user_id', 'item_id', 'rating']
    df_vector['rating'] = df_vector['rating'] / scaler
    df_vector['user_id'] = df_vector['user_id'].apply(lambda x: user_index[x])
    print(df_vector)
    return df_vector


def evaluation(y_true, y_pred):
    '''
    模型评估:获取准确率、精准度、召回率、F1-score值
    y_true:正确标签
    y_pred:预测标签
    '''
    accuracy = round(classification_report(y_true, y_pred, output_dict=True)['accuracy'], 3)  # 准确率
    s = classification_report(y_true, y_pred, output_dict=True)['weighted avg']
    precision = round(s['precision'], 3)  # 精准度
    recall = round(s['recall'], 3)  # 召回率
    f1_score = round(s['f1-score'], 3)  # F1-score
    print('神经网络协同推荐(NCF):准确率是{},精准度是{},召回率是{},F1值是{}'.format(accuracy, precision, recall, f1_score))
    return accuracy, precision, recall, f1_score


def get_data_fit(df_vector):
    '''
    数据训练,得到模型
    '''
    scaler = 5  # 特征标准化:最高分为5,需要归一化到0~1
    dataset = df_vector  # 已向量化的数据集
    # 使用LabelEncoder将字符串标签转换为整数标签
    user_encoder = LabelEncoder()
    item_encoder = LabelEncoder()
    dataset['user_id'] = user_encoder.fit_transform(dataset['user_id'])
    dataset['item_id'] = item_encoder.fit_transform(dataset['item_id'])

    # Split the dataset into train and test sets
    train, test = train_test_split(dataset, test_size=0.2, random_state=42)  # 划分训练集与测试集
    # train = dataset

    # Model hyperparameters
    num_users = len(dataset['user_id'].unique())
    num_countries = len(dataset['item_id'].unique())

    embedding_dim = 64  # 64维向量标识

    # 创建NCF模型
    inputs_user = tf.keras.layers.Input(shape=(1,))
    inputs_item = tf.keras.layers.Input(shape=(1,))
    embedding_user = tf.keras.layers.Embedding(num_users, embedding_dim)(inputs_user)
    embedding_item = tf.keras.layers.Embedding(num_countries, embedding_dim)(inputs_item)

    # 合并 embeddings向量
    merged = tf.keras.layers.Concatenate()([embedding_user, embedding_item])
    merged = tf.keras.layers.Flatten()(merged)

    # 添加全连接层
    dense = tf.keras.layers.Dense(64, activation='relu')(merged)
    dense = tf.keras.layers.Dense(32, activation='relu')(dense)
    output = tf.keras.layers.Dense(1, activation='sigmoid')(dense)

    # 编译模型
    model = tf.keras.Model(inputs=[inputs_user, inputs_item], outputs=output)
    model.compile(optimizer='adam', loss='mse', metrics=['mae'])
    # 模型训练
    model.fit(
        [train['user_id'].values, train['item_id'].values],
        train['rating'].values,
        batch_size=64,
        epochs=100,
        verbose=0,
        # validation_split=0.1,
    )


    item_rates = RateCourse.objects.all().values('course_id').distinct()
    # 获取每个用户的评分数据
    result_df = {}
    for user in User.objects.all():
        user_rate = RateCourse.objects.filter(user=user)
        if not user_rate:
            # 用户如果没有评分过任何一本课程则跳过循环
            continue
        user = f'user_{user.id}'
        result_df[user] = {}
        for br in item_rates:
            item_id = br['course_id']
            item = f'item_{item_id}'
            pred_user_id = user_encoder.transform([user])
            pred_item_id = item_encoder.transform([item])
            result = model.predict(x=[pred_user_id, pred_item_id], verbose=0)
            result_df[user][item] = result[0][0]
    result_df = pd.DataFrame(result_df).T
    result_df *= scaler

    print('全部用户预测结果', result_df)

    # 预测测试集并转成整形列表
    y_pred_ = np.floor(model.predict(x=[test['user_id'], test['item_id']], verbose=0) * scaler).tolist()
    y_pred = []
    for y in y_pred_:
        y_pred.append(int(y[0]))
    y_true = (test['rating'] * scaler).tolist()
    evaluation(y_true, y_pred)  # 模型评估
    joblib.dump(user_encoder, 'user_encoder.pkl')  # 保存用户标签
    joblib.dump(item_encoder, 'item_encoder.pkl')  # 保存课程标签
    model.save('ncf.dat')  # 模型保存

def get_ncf_recommend(user_id, n=10):
    '''
    # 获取推荐
    user_id:用户id
    n:只取前十个推荐结果
    '''
    scaler = 5  # 特征标准化:最高分为5,需要归一化到0~1
    model = load_model('ncf.dat')  # 加载模型
    # 加载标签
    user_encoder = joblib.load('user_encoder.pkl')
    item_encoder = joblib.load('item_encoder.pkl')

    result_df = {}
    item_rates = RateCourse.objects.all().values('course_id').distinct()
    for item in item_rates:
        item_id = item['course_id']
        user = f'user_{user_id}'
        item = f"item_{item_id}"
        pred_user_id = user_encoder.transform([user])
        pred_item_id = item_encoder.transform([item])
        result = model.predict(x=[pred_user_id, pred_item_id], verbose=0)
        if not RateCourse.objects.filter(user_id=user_id, course_id=item_id):
            # 过滤掉用户已评分过的
            result_df[item_id] = result[0][0] * scaler
    result_df_sort = sorted(result_df.items(), key=lambda x: x[1], reverse=True)  # 推荐结果按照评分降序排列
    print('预测结果', result_df_sort)
    recommend_ids = []
    for rds in result_df_sort[:n]:
        recommend_ids.append(rds[0])
    print(f'前{n}个推荐结果', recommend_ids)
    return recommend_ids


if __name__ == '__main__':
    data_pd = get_all_data()  # 获取数据
    df_vector = get_data_vector(data_pd)  # 数据向量化
    data_recommend = get_data_fit(df_vector)  # 获取数据训练模型
    user_id = 1
    recommend_ids = get_ncf_recommend(user_id)  # 获取用户1的推荐结果

4、数据概览

在这里插入图片描述

5、数据导入

流程:
1、保存上一个用户
2、创建学生信息,用户名就是学生编号,密码是123456
3、更新课程序号
4、创建选课记录
5、添加用户喜欢的课程类型
6、更改上一个用户
7、

def import_data(request):
    with open('data/data.csv', 'r', newline='', encoding='gbk') as fp:
        reader = csv.reader(fp)
        user_last = None  # 上一个用户
        tag_id = []
        for row in reader:
            user_id = row[0]
            if user_id == 'stu_id':
                continue
            if not user_last:
                user_last = user_id
            users = User.objects.filter(username=user_id)
            if not users:
                user = User.objects.create(username=user_id, password='123456')  # 创建学生信息,用户名就是学生编号,密码是123456
            else:
                user = users.first()
            # 查找课程
            course_infos = CourseInfo.objects.filter(name=row[3])
            if not course_infos:
                continue
            course = course_infos.first()
            if not course.course_index:
                course.course_index = row[2] # 更新课程序号
                course.save()
            if not UserCourse.objects.filter(user=user, course=course):
                # 创建选课记录
                UserCourse.objects.create(
                    user_id=user.id,
                    course_id=course.id,
                    std_id=row[0],
                    course_index=row[2],
                    enroll_time=row[1]
                )
                course.select_num += 1
                course.look_num += 1
                course.save()
                if user_id != user_last:
                    # 添加用户喜欢的课程类型
                    user_select = UserSelectTypes.objects.filter(user=User.objects.get(username=user_last))
                    if not user_select:
                        user_select = UserSelectTypes.objects.create(user=User.objects.get(username=user_last))
                    else:
                        user_select = user_select.first()
                    for value in tag_id:
                        user_select.category.add(value)
                    user_last = user_id  # 更改上一个用户
                    tag_id = []
                else:
                    tag_id.append(course.tags_id)
                print('创建选课记录成功', user_id, row[3])
            else:
                course.select_num += 1
                course.look_num += 1
                course.save()
    return HttpResponse('导入成功')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1859304.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024 CISCN 华东北分区赛-Ahisec

Ahisec战队 WEB python-1 break 源码如下: # -*- coding: UTF-8 -*-from flask import Flask, request,render_template,render_template_stringapp Flask(__name__)def blacklist(name):blacklists ["print","cat","flag",&q…

【嵌入式Linux】<总览> 多进程(更新中)

文章目录 前言 一、进程的概念与结构 1. 相关概念 2. 内核区中的进程结构 3. 进程的状态 4. 获取进程ID函数 二、进程创建 1. fork和vfork函数 2. 额外注意点 3. 构建进程链 4.构建进程扇 三、进程终止 1. C程序的启动过程 2. 进程终止方式 四、特殊的进程 1. 僵…

AppInventor2添加超过10个屏幕会怎样?

之前发过一篇AppInventor2官方翻译文档,建议一个项目不要超过10个屏幕,详见: App Inventor 2 构建多屏幕App的最佳实践 App Inventor 可以轻松地向应用程序添加更多屏幕,但最好也不要添加太多屏幕,因为多个屏幕的应用…

U盘数据恢复全攻略:从原理到实践

一、引言:为何U盘数据恢复至关重要 在信息化时代,U盘作为便携存储设备,广泛应用于各个领域。然而,U盘数据的丢失往往给个人和企业带来极大的困扰。数据丢失的原因多种多样,可能是误删除、格式化、文件系统损坏&#x…

探索约束LLM输出JSON的应用

0、 引言 JSON(JavaScript Object Notation)因其简洁、易读和易于解析的特性,已成为全球使用最广泛的数据交换格式之一。它能够满足各种数据交换需求,特别是在构建人工智能驱动的应用程序时,工程师们经常需要将大型语…

Jenkins教程-8-上下游关联自动化测试任务构建

上一小节小节我们学习了一下Jenkins自动化测试任务发送测试结果邮件的方法,本小节我们讲解一下Jenkins上下游关联自动化测试任务的构建。 下面我们以一个真实的自动化测试场景来讲解Jenkins如何管理上下游关联任务的触发和构建,比如我们有两个jenkin任务…

基础入门篇 | YOLOv10 项目【训练】【验证】【推理】最简单教程 | YOLOv10必看 | 最新更新,直接打印 FPS,mAP50,75,95

文章目录 训练 --train.py推理 --detect.py验证 --val.py不训练,只查看模型结构/参数量/计算量 --test.pyYOLOv10 是基于 YOLOv8 项目的改进版本,目前已经被 YOLOv8 项目合并,所以两个算法使用方法完全一致~ 今天我给大家展示一种非常方便的使用过程,包含【训练】【验证】…

情绪管理篇:让七情自然流露,不过分压抑也不掺杂极端的想法即可来去自如

情绪管理篇: 人有七情,本属常理,该哭的时候哭、该笑的时候笑、该怒的时候怒、该忧的时候忧 学习圣贤之学,并非让我们像木头人一样,枯木死灰,而要让自己不要被七情所缠缚、被七情所乱心,我们的喜…

QT拖放事件之三:自定义拖放操作-利用QDrag来拖动完成数据的传输

1、运行效果 1)Qt::MoveAction 2)Qt::CopyAction 2、源码 #include "Widget.h" #include "ui_Widget.h" #include "common.h"

JDBC的概念 ,核心API的介绍 , 注册驱动介绍

第一章 JDBC 1、JDBC的概念 目标 能够掌握JDBC的概念能够理解JDBC的作用 讲解 客户端操作MySQL数据库的方式 使用第三方客户端来访问MySQL:SQLyog、Navicat 使用MySQL自带的命令行方式 通过Java来访问MySQL数据库,今天要学习的内容 如何通过Java代…

考研数学|《李林880》正确率多少算合格?

李林880题是针对考研数学三的练习题集,覆盖了考研数学三的主要知识点和题型。如果能够熟练掌握这些题目,意味着对考研数学三的知识点有了较为深入的理解和应用能力。 首先,考研数学三的总分是150分,题型包括单选题、填空题和解答…

Day5 —— 电商日志数据分析项目

项目二 _____(电商日志数据分析项目) 引言需求分析详细思路统计页面浏览量Map阶段Reduce阶段 日志的ETL操作Map阶段Reduce阶段 统计各个省份的浏览量Map阶段Reduce阶段 具体步骤统计页面浏览量日志的ETL操作统计各个省份的浏览量工具类(utils…

鸿蒙HarmonyOS服务卡片实战

引言 在现代开发中,服务卡片是不可或缺的一部分,比如音乐,天气类等应用,官网的介绍中写道:卡片让您便捷地预览服务信息,例如查看天气或日历日程等内容。您可将卡片添加到屏幕上,让这类信息触手…

拼多多面试总结

文章目录 一面自我介绍提问算法反问结果 二面提问算法反问结果 主管面主管面试准备算法题其他个人提问准备 提问数据库普通索引和覆盖索引的区别索引是什么?索引怎么加快数据库查询的?索引具体怎么实现的?以B树为例,节点放了什么&…

SOIDWORKS Electrical中统计槽满率的经验技巧

近期有一些客户咨询,为什么在SOLIDWORKS Electrical 3D 中做完3D布线工作,但是在统计线槽槽满率的时候不能正常计算。因此我们总结了以下几点经验。 一、对于SOLIDWORKS Electrical中的计算线槽率的功能,除了所使用的线槽需要满足两个条件&am…

【Unity服务器01】之【AssetBundle上传加载u3d模型】

首先打开一个项目导入一个简单的场景 导入怪物资源, AssetBundle知识点: 1.指定资源的AssetBundle属性标签 (1)找到AssetBundle属性标签 (2)A标签 代表:资源目录(决定打包之后在哪…

LDO电源模块如何快速设计布局

在现代电子设备遍布的时代,电源模块的设计与应用成为了电子工程领域中的核心议题。而LDO(低压差线性稳压器)电源模块,因其出色的线性特性和稳定性,在众多应用中备受青睐。为了满足不断增长的电子设备性能需求&#xff…

控价服务商的选择标准

品牌控价旨在对渠道进行有效管控,维护品牌自身价值以及经销商的合法权益,同时也为消费者提供稳定的购物价格。在这一过程中,不但要对线上价格进行把控,线下价格同样需要品牌投入精力去管理。就线上而言,由于链接数量众…

面向对象的进阶---static

1.static 静态变量 package com.itheima.a01staticdemo01;public class Student {private String name;private int age;public static String teacherName;public Student() {}public Student(String name, int age) {this.name name;this.age age;}/*** 获取* return n…

基于单片机的智能台灯控制系统

摘要: 文章设计一款单片机智能台灯控制系统,实现对台灯的手动和自动控制功能,以 STC89C52 单片机作为多功能智能台灯的主控制器,光电检测模块检测坐姿,红外传感器检测人体,光敏电阻检测光强,同…