背景与意义
校园餐饮服务是学生日常生活的重要组成部分,但传统餐饮模式存在选择单一、排队时间长、口味匹配度低等问题。基于Django框架和K-means算法的校园美食推荐系统,旨在通过数据驱动的方式优化餐饮体验,提升食堂运营效率与学生满意度。
技术背景
- Django框架:作为Python的高效Web开发框架,Django提供快速构建、安全性和可扩展性,适合处理用户数据与推荐逻辑。
- K-means算法:一种无监督聚类算法,通过分析用户历史消费数据(如菜品偏好、消费频率等),将相似口味的学生分组,实现个性化推荐。
实际意义
- 学生侧:减少盲目选择时间,推荐符合个人口味的菜品,提升就餐满意度。
- 食堂侧:通过数据分析预测热门菜品,优化备餐量,降低浪费;动态调整窗口分配,缓解排队压力。
- 数据价值:长期积累的用户行为数据可为校园餐饮规划(如新菜品开发、档口布局)提供决策支持。
创新性
将机器学习算法与校园场景结合,弥补传统推荐系统在高校餐饮领域的空白,为智慧校园建设提供实践案例。
技术栈概述
Django框架结合K-means算法实现校园美食推荐系统,涉及前后端开发、数据处理及机器学习集成。以下是关键技术和工具:
后端开发
- Django:作为核心Web框架,提供MVC架构、ORM、路由管理和模板渲染。
- Django REST Framework:用于构建推荐系统的API接口,支持JSON数据交互。
- Python科学计算库:
scikit-learn实现K-means聚类算法,pandas和numpy处理数据预处理。
前端开发
- HTML/CSS/JavaScript:基础前端三件套,构建用户界面。
- Bootstrap:快速响应式布局,适配移动端。
- Vue.js/React(可选):增强交互体验,动态展示推荐结果。
数据库
- PostgreSQL/MySQL:存储用户信息、菜品数据及评分记录。
- Redis:缓存热门推荐结果,减少实时计算压力。
机器学习集成
- K-means算法:基于用户历史行为(如评分、下单频率)聚类,生成相似用户群体。
- 特征工程:提取菜品口味、价格、时段等特征,标准化后输入模型。
- 模型持久化:
joblib或pickle保存训练好的聚类模型,避免重复计算。
部署与运维
- Nginx + Gunicorn:生产环境部署Django应用。
- Celery:异步处理聚类任务,避免阻塞主线程。
- Docker:容器化部署,简化依赖管理和扩展。
辅助工具
- Jupyter Notebook:算法原型开发和调试。
- Git:版本控制和团队协作。
- Prometheus/Grafana(可选):监控系统性能及推荐效果。
该系统通过K-means分析用户行为模式,结合Django的高效开发能力,实现个性化美食推荐。
数据预处理与特征提取
从数据库中获取用户历史订单数据,清洗并提取特征(如菜品类别、价格、评分等)。使用Django的ORM查询数据:
from django.db.models import Count from user.models import Order, FoodItem # 获取用户历史订单数据 def get_user_orders(user_id): orders = Order.objects.filter(user_id=user_id).select_related('food_items') return orders # 构建特征矩阵 def build_feature_matrix(): food_items = FoodItem.objects.all() features = [] for item in food_items: features.append([ item.category_id, # 类别特征 float(item.price), # 价格特征 item.avg_rating # 评分特征 ]) return np.array(features)K-means聚类实现
使用scikit-learn实现K-means算法,对菜品进行聚类:
from sklearn.cluster import KMeans import numpy as np # 初始化K-means模型 def train_kmeans(feature_matrix, n_clusters=5): kmeans = KMeans(n_clusters=n_clusters, random_state=42) kmeans.fit(feature_matrix) return kmeans # 预测新菜品所属聚类 def predict_cluster(kmeans_model, new_item_features): cluster = kmeans_model.predict([new_item_features])[0] return cluster推荐逻辑实现
基于用户历史订单和聚类结果生成推荐:
# 获取用户偏好聚类 def get_user_preferred_clusters(user_id): orders = get_user_orders(user_id) clusters = [] for order in orders: for item in order.food_items.all(): features = [item.category_id, float(item.price), item.avg_rating] cluster = predict_cluster(kmeans_model, features) clusters.append(cluster) # 返回用户最常点的前3个聚类 from collections import Counter top_clusters = [c for c, _ in Counter(clusters).most_common(3)] return top_clusters # 生成推荐 def generate_recommendations(user_id, kmeans_model, n_recommendations=5): preferred_clusters = get_user_preferred_clusters(user_id) all_food_items = FoodItem.objects.all() # 筛选不属于用户已点过的菜品 ordered_items = set() for order in get_user_orders(user_id): ordered_items.update(order.food_items.all()) recommendations = [] for item in all_food_items: if item not in ordered_items: features = [item.category_id, float(item.price), item.avg_rating] cluster = predict_cluster(kmeans_model, features) if cluster in preferred_clusters: recommendations.append(item) # 按评分排序返回推荐结果 return sorted(recommendations, key=lambda x: x.avg_rating, reverse=True)[:n_recommendations]视图层集成
将推荐系统集成到Django视图中:
from django.http import JsonResponse from .recommendation import generate_recommendations def recommend_food(request): if not request.user.is_authenticated: return JsonResponse({'error': 'Authentication required'}, status=401) # 加载预训练的K-means模型 import joblib kmeans_model = joblib.load('kmeans_model.pkl') recommendations = generate_recommendations(request.user.id, kmeans_model) data = [{ 'id': item.id, 'name': item.name, 'price': str(item.price), 'rating': item.avg_rating } for item in recommendations] return JsonResponse({'recommendations': data})模型训练与更新
定期重新训练模型的Celery任务:
from celery import shared_task from .models import FoodItem from .recommendation import train_kmeans, build_feature_matrix @shared_task def retrain_kmeans_model(): feature_matrix = build_feature_matrix() kmeans_model = train_kmeans(feature_matrix) # 保存新模型 import joblib joblib.dump(kmeans_model, 'kmeans_model.pkl')该系统核心在于通过K-means聚类分析用户饮食偏好,基于聚类结果推荐相似菜品。注意需要定期更新模型以反映最新的菜品和用户行为数据。
Django 基于 K-means 算法的校园美食推荐系统设计
数据库设计
数据库设计需围绕用户行为、菜品属性和聚类结果展开,核心表结构如下:
用户表(User)
user_id(PrimaryKey): 用户唯一标识username: 用户名password: 加密后的密码email: 用户邮箱preferences: JSON 字段,存储用户初始饮食偏好(如忌口、口味)
菜品表(Food)
food_id(PrimaryKey): 菜品唯一标识name: 菜品名称price: 价格category: 分类(如快餐、面食)tags: JSON 字段,存储菜品特征(如辣度、甜度、热量)
用户行为表(UserBehavior)
behavior_id(PrimaryKey): 行为记录IDuser_id(ForeignKey): 关联用户food_id(ForeignKey): 关联菜品rating: 评分(1-5分)timestamp: 行为时间戳
聚类结果表(ClusterResult)
cluster_id: 聚类分组IDfood_ids: JSON 数组,存储该聚类下的菜品ID列表centroid: JSON 字段,存储聚类中心特征向量
K-means 算法实现
通过菜品特征(如价格、辣度、热量)构建特征向量,使用scikit-learn实现聚类:
from sklearn.cluster import KMeans import numpy as np # 示例:从数据库加载菜品特征 food_features = Food.objects.values_list('price', 'spicy_level', 'calories') X = np.array(list(food_features)) # 聚类(假设分为5类) kmeans = KMeans(n_clusters=5, random_state=42) kmeans.fit(X) # 保存聚类结果到数据库 for i in range(5): cluster_food_ids = Food.objects.filter( pk__in=np.where(kmeans.labels_ == i)[0] ).values_list('food_id', flat=True) ClusterResult.objects.create( cluster_id=i, food_ids=list(cluster_food_ids), centroid=kmeans.cluster_centers_[i].tolist() )推荐逻辑
- 用户画像匹配:根据用户历史评分行为,计算其偏好向量(如平均辣度、价格敏感度)。
- 聚类匹配:找到与用户偏好最接近的聚类中心(欧氏距离最小)。
- 推荐生成:从匹配的聚类中随机选取未评分菜品,或按热度排序。
def recommend_foods(user_id, top_n=5): user_prefs = calculate_user_preferences(user_id) # 自定义函数计算用户偏好 clusters = ClusterResult.objects.all() best_cluster = min(clusters, key=lambda c: np.linalg.norm(np.array(c.centroid) - user_prefs)) recommended = Food.objects.filter( food_id__in=best_cluster.food_ids ).exclude( userbehavior__user_id=user_id )[:top_n] return recommended系统测试方案
单元测试
- 测试聚类算法:验证输入特征矩阵后,聚类结果是否符合预期分布。
- 测试推荐逻辑:模拟用户行为数据,检查推荐菜品是否匹配预期聚类。
from django.test import TestCase from sklearn.metrics import silhouette_score class ClusteringTest(TestCase): def test_kmeans_output(self): X = np.random.rand(100, 3) # 模拟100个菜品特征 kmeans = KMeans(n_clusters=5).fit(X) self.assertEqual(len(np.unique(kmeans.labels_)), 5) self.assertGreater(silhouette_score(X, kmeans.labels_), 0) # 轮廓系数验证集成测试
- 用户行为流:模拟用户从登录、评分到获取推荐的完整流程。
- 数据一致性:检查聚类结果表与菜品表的关联数据是否同步更新。
性能测试
- 使用
django-debug-toolbar监控推荐接口响应时间,确保在100ms内返回结果。 - 模拟高并发请求,验证聚类计算的缓存机制(如每日凌晨更新聚类)。
注意事项
- 特征工程需标准化(如
StandardScaler),避免量纲影响聚类。 - 冷启动问题:新用户或无历史数据时,采用热门菜品或随机推荐。
- 定期重新聚类(如每周),反映菜品更新或用户偏好变化。