1. 考察知识点: 本次 Lab 主要考察 Python 语言的核心基础知识,包括但不限于:
2. 重要提醒:严禁使用外部库
本实验的核心目的是巩固对 Python 原生语言特性的掌握程度。因此,在完成本次 Lab 的所有任务时,只能使用 Python 标准库提供的数据结构和内置函数,严禁导入和使用任何外部第三方库(如 pandas, numpy 等)。 如果在代码中发现使用违规库,该项任务将会被判定为 0 分。
3. 关于测试与评分机制的说明:
Notebook 中每个任务下方提供的 assert 测试单元格,仅仅是作为基础的辅助检查,用来帮助大家快速排查低级错误或拼写问题。通过了 Notebook 中的可见测试,绝对不代表你的代码逻辑100%正确,也不保证能拿满分。
在最终提交评测时,我们会使用一套包含更多边界情况、异常值和隐藏数据集的 assert 测试脚本进行自动化打分。请大家务必在写代码时自行考虑逻辑的严密性和代码的健壮性。
欢迎加入本学期的实战项目!在这个 Lab 中,你将扮演「THU Eats 校园美食指南」项目组的数据分析师(Data Scientist)。我们的目标是开发一款专为清华学子打造的美食推荐引擎,帮助大家更高效地探索周边美食。
作为团队的核心技术骨干,你需要利用 Python 处理从真实点评平台上获取的餐厅数据,完成从基础数据统计、商业市场分析到核心推荐算法的开发。
准备好开启你的数据科学之旅了吗?
评分规则: 共 100 分(9 道编程题)。
通关提示: 每道题都要求你在代码块中写出完整的逻辑。请删除 raise NotImplementedError() 并填入你的代码。运行测试块,如果没有报错即代表基础步骤通过测试。
首先,我们将项目组采集到的结构化数据加载到内存中。请直接运行下面的代码块,无需修改。
# 请直接运行此单元格,不要修改
restaurants = [
{"name": "海底捞(五道口店)", "cuisine": "火锅", "price": 120, "rating": 4.5, "reviews": 2890, "delivery": True, "district": "五道口"},
{"name": "一兰拉面", "cuisine": "日料", "price": 68, "rating": 4.7, "reviews": 1560, "delivery": False, "district": "五道口"},
{"name": "鲍师傅糕点", "cuisine": "烘焙", "price": 25, "rating": 4.3, "reviews": 3200, "delivery": True, "district": "五道口"},
{"name": "喜茶(清华店)", "cuisine": "饮品", "price": 30, "rating": 4.1, "reviews": 1890, "delivery": True, "district": "五道口"},
{"name": "西少爷肉夹馍", "cuisine": "快餐", "price": 22, "rating": 4.0, "reviews": 950, "delivery": True, "district": "五道口"},
{"name": "探鱼(学院路店)", "cuisine": "烤鱼", "price": 85, "rating": 4.4, "reviews": 1120, "delivery": False, "district": "学院路"},
{"name": "麦当劳(清华东门)", "cuisine": "快餐", "price": 35, "rating": 3.8, "reviews": 2100, "delivery": True, "district": "五道口"},
{"name": "呷哺呷哺(五道口)", "cuisine": "火锅", "price": 65, "rating": 4.0, "reviews": 1780, "delivery": True, "district": "五道口"},
{"name": "Luckin Coffee", "cuisine": "饮品", "price": 18, "rating": 3.9, "reviews": 890, "delivery": True, "district": "清华校内"},
{"name": "紫光园(蓝旗营)", "cuisine": "清真", "price": 45, "rating": 4.2, "reviews": 760, "delivery": False, "district": "蓝旗营"},
{"name": "芙蓉园餐厅", "cuisine": "食堂", "price": 15, "rating": 4.0, "reviews": 1200, "delivery": False, "district": "清华校内"},
{"name": "观畴园餐厅", "cuisine": "食堂", "price": 12, "rating": 3.9, "reviews": 1500, "delivery": False, "district": "清华校内"},
{"name": "Manner Coffee", "cuisine": "饮品", "price": 20, "rating": 4.3, "reviews": 650, "delivery": False, "district": "五道口"},
{"name": "烤匠(五道口店)", "cuisine": "烧烤", "price": 95, "rating": 4.6, "reviews": 980, "delivery": False, "district": "五道口"},
{"name": "木屋烧烤(学院路)", "cuisine": "烧烤", "price": 88, "rating": 4.2, "reviews": 1340, "delivery": True, "district": "学院路"},
{"name": "太二酸菜鱼", "cuisine": "酸菜鱼", "price": 78, "rating": 4.5, "reviews": 2050, "delivery": False, "district": "五道口"},
{"name": "清华丁香餐厅", "cuisine": "食堂", "price": 18, "rating": 4.1, "reviews": 900, "delivery": False, "district": "清华校内"},
{"name": "南门烧烤", "cuisine": "烧烤", "price": 55, "rating": 3.7, "reviews": 430, "delivery": True, "district": "蓝旗营"},
{"name": "望京小腰(学院路)", "cuisine": "烧烤", "price": 75, "rating": 4.1, "reviews": 870, "delivery": True, "district": "学院路"},
{"name": "必胜客(五道口店)", "cuisine": "西餐", "price": 70, "rating": 3.6, "reviews": 1100, "delivery": True, "district": "五道口"}
]
print(f"数据加载成功!共获取了 {len(restaurants)} 家餐厅的数据样本。")
print(f"每家餐厅的数据字段包括: {list(restaurants[0].keys())}")
print(f"\n样例数据预览: {restaurants[0]}")
项目启动会上,产品负责人需要一份整体的“校园周边餐饮宏观数据”。你需要帮团队快速计算出核心指标。
请编写代码,完成以下计算:
avg_price(浮点数)best_restaurant(字符串)delivery_count(整数)"共X家餐厅,平均消费Y元,其中Z家支持外卖",赋值给变量 summary提示: Python 的内置函数
sum(),len(),max()将非常有帮助。
# YOUR CODE HERE
raise NotImplementedError()
print(f"avg_price = {avg_price}")
print(f"best_restaurant = {best_restaurant}")
print(f"delivery_count = {delivery_count}")
print(f"summary = {summary}")
assert isinstance(avg_price, float), "avg_price 应为浮点数"
assert isinstance(best_restaurant, str), "best_restaurant 应为字符串"
assert isinstance(delivery_count, int), "delivery_count 应为整数"
assert "平均消费" in summary and "支持外卖" in summary, "summary 格式不正确"
print("Q1 项目简报数据生成基础测试通过!")
为了给不同预算预期的同学提供精准推荐,运营团队需要为数据库中的餐厅增加消费分级标签。
请编写一个代码块,遍历 restaurants 列表,为每家餐厅生成一个分类标签,规则如下:
price >= 80,标签为 "高档"30 <= price < 80,标签为 "中档"price < 30,标签为 "平价"预期输出:
classified,每个字典包含两个键:"name": 餐厅名称, "level": 分类标签[{"name": "海底捞(五道口店)", "level": "高档"}, ...]high_countbudget_count# YOUR CODE HERE
raise NotImplementedError()
print(f"分类结果前5条: {classified[:5]}")
print(f"高档: {high_count} 家, 平价: {budget_count} 家")
assert isinstance(classified, list) and len(classified) == 20
assert all("name" in c and "level" in c for c in classified), "每条记录必须包含 name 和 level"
assert classified[0]["level"] == "高档", "海底捞 price=120 应为高档"
assert high_count == len([r for r in restaurants if r["price"] >= 80]), "high_count 统计数量有误"
assert budget_count == len([r for r in restaurants if r["price"] < 30]), "budget_count 统计数量有误"
print("Q2 餐厅标签系统构建基础测试通过!")
产品经理提出了三个 App 首页“探索频道”的特色功能需求。你需要通过基础逻辑来实现它们。
请编写代码,严格使用循环结构(for / while)完成以下任务:
popular。while 循环,从列表开头开始查找,遇到第一家不支持外卖的店即停止,将其名称赋值给 first_no_delivery。enumerate 遍历餐厅列表,提取所有索引为偶数(0, 2, 4...)的餐厅名称,存入列表 even_index_names。# YOUR CODE HERE
raise NotImplementedError()
print(f"高分人气榜: {popular}")
print(f"推荐线下体验: {first_no_delivery}")
print(f"偶数索引数据: {even_index_names}")
assert isinstance(popular, list), "popular 应为列表"
assert isinstance(first_no_delivery, str), "first_no_delivery 应为字符串"
assert first_no_delivery == "一兰拉面", "线下体验门店查找错误,应为列表里第一家不支持外卖的店"
assert len(even_index_names) == 10, "偶数索引应有 10 个元素(索引 0,2,...,18)"
assert even_index_names[0] == "海底捞(五道口店)" and even_index_names[1] == "鲍师傅糕点", "前端排版测试数据提取有误"
print("Q3 探索频道功能逻辑基础测试通过!")
平台计划上线“高性价比专区”,帮助同学们在保证体验的同时合理控制花销。我们需要通过列表切片和推导式技术来处理数据。
rating)从高到低排序(如果评分相同,保持原列表的默认顺序即可),切片取出排名前5的餐厅名称,存入列表 top5_names。restaurants 列表中第3到第7家(即索引 2 到 6,含两端)的餐厅,将它们的人均消费单独提取出来,存入列表 prices_slice。affordable_delivery,包含所有 人均消费 < 50 且支持外卖 的餐厅名称。提示:
sorted()函数可以通过key=lambda ...和reverse=True参数轻松完成自定义的高阶排序。
# YOUR CODE HERE
raise NotImplementedError()
print(f"评分前5名: {top5_names}")
print(f"抽样数据价格: {prices_slice}")
print(f"平价外卖清单: {affordable_delivery}")
assert isinstance(top5_names, list) and len(top5_names) == 5
assert top5_names[0] == "一兰拉面", "评分第一名应该是一兰拉面"
assert isinstance(prices_slice, list) and len(prices_slice) == 5
assert prices_slice == [25, 30, 22, 85, 35], "抽样数据价格提取有误"
assert isinstance(affordable_delivery, list)
assert "西少爷肉夹馍" in affordable_delivery and "海底捞(五道口店)" not in affordable_delivery, "平价外卖逻辑有误"
print("Q4 高性价比专区数据处理基础测试通过!")
商业分析师(Business Analyst)正在撰写周边餐饮环境调研报告,需要了解目前市场的主流菜系和品类均价。
请使用字典(Dictionary)进行数据聚合计算:
cuisine_count,记录每种菜系有多少家餐厅(例:{"火锅": 2, "日料": 1})。cuisine_avg_price,计算出每种菜系的平均人均消费。most_common_cuisine。# YOUR CODE HERE
raise NotImplementedError()
print(f"品类分布: {cuisine_count}")
print(f"品类价格指数: {cuisine_avg_price}")
print(f"周边最主流品类: {most_common_cuisine}")
assert isinstance(cuisine_count, dict) and isinstance(cuisine_avg_price, dict)
assert isinstance(most_common_cuisine, str)
assert cuisine_count["火锅"] == 2, "火锅应有 2 家"
print("Q5 商业分析数据聚合基础测试通过!")
战略规划部需要对比“五道口(社会餐饮为主)”和“清华校内(食堂为主)”的餐饮生态差异,为未来的推荐算法添加区域权重属性。
这正是 Python 集合(Set) 大显身手的时候!请计算:
wudaokou_cuisines,提取五道口区域所有不重复的菜系。campus_cuisines,提取清华校内区域所有不重复的菜系。only_wudaokou。shared_cuisines。all_cuisines。# YOUR CODE HERE
raise NotImplementedError()
print(f"五道口特色菜系: {only_wudaokou}")
print(f"双方共有的菜系: {shared_cuisines}")
print(f"全域餐饮品类: {all_cuisines}")
assert isinstance(wudaokou_cuisines, set) and isinstance(campus_cuisines, set)
assert isinstance(only_wudaokou, set) and isinstance(shared_cuisines, set) and isinstance(all_cuisines, set)
print("Q6 区域餐饮生态对比基础测试通过!")
为了支撑后续更复杂的功能,我们需要将常用的查询逻辑封装成稳定可靠的函数 (Functions),构建后端 API 的基础组件。
请定义以下两个组件:
组件 1: 筛选引擎 filter_restaurants(data, min_rating=4.0, max_price=100, cuisine=None)
data,并过滤出满足条件的餐厅:min_rating (默认 4.0)max_price (默认 100)cuisine (默认为 None 时表示不限制菜系)组件 2: 统计面板 restaurant_summary(data)
data,返回一个包含3个元素的元组 (Tuple): (餐厅总数量, 平均人均消费, 平均评分)。data 是空的,请直接返回 (0, 0.0, 0.0),防止出现除以零的错误。# YOUR CODE HERE
raise NotImplementedError()
# 模拟模块调用测试
hotpot = filter_restaurants(restaurants, cuisine="火锅", max_price=200)
print(f"查询火锅 (预算充足): {[r['name'] for r in hotpot]}")
cheap_good = filter_restaurants(restaurants, min_rating=4.0, max_price=30)
print(f"查询平价好评: {[r['name'] for r in cheap_good]}")
result = restaurant_summary(restaurants)
print(f"全局统计信息: 数量={result[0]}, 均价={result[1]:.1f}, 均分={result[2]:.2f}")
assert callable(filter_restaurants) and callable(restaurant_summary)
assert isinstance(filter_restaurants(restaurants), list)
result = restaurant_summary(restaurants)
assert isinstance(result, tuple) and len(result) == 3
assert restaurant_summary([]) == (0, 0.0, 0.0), "防御性编程测试失败:传入空列表时应返回 (0, 0.0, 0.0)"
print("Q7 基础查询与统计组件封装基础测试通过!")
AI 算法团队计划引入机器学习模型进行深度偏好分析,他们的训练管道需要 .csv 格式的结构化数据。你需要负责将内存中的数据持久化存储。
第一段管线:写入导出
将 restaurants 数据写入文件 restaurants_export.csv,要求:
open() 函数读写文件时,请务必添加参数 encoding='utf-8',以防中文字符乱码。name,cuisine,price,rating,reviews,delivery,districtdelivery 字段目前是 True/False,请转换为数值 1 或 0,以便模型更好地处理。第二段管线:读取校验
请读取刚生成的 restaurants_export.csv 进行数据完整性验证:
csv_lines。csv_restaurant_count。# YOUR CODE HERE
raise NotImplementedError()
print(f"数据导出完成,成功校验 {csv_restaurant_count} 条记录。")
print(f"抽检前3行数据: {csv_lines[:3]}")
import os
assert os.path.exists("restaurants_export.csv"), "文件 restaurants_export.csv 不存在"
assert isinstance(csv_lines, list) and isinstance(csv_restaurant_count, int)
print("Q8 数据 IO 管道基础测试通过!")
这是本期 Lab 的最终挑战!你需要综合运用前面的知识,构建推荐系统的核心逻辑模块。
请编写函数 recommend(data, budget, preferences, top_n=3),根据用户的多维度需求进行精准匹配:
price > budget 的餐厅。preferences。如果传入了 "cuisine"、"delivery" 或 "district" 特征(可能部分缺失),则餐厅必须同时满足这些提供的条件(即取交集),不符合的直接筛选掉。rating 从高到低 进行排序。top_n 的餐厅名称列表(若符合条件的数量不足 top_n,则返回全部符合条件的列表)。def recommend(data, budget, preferences, top_n=3):
# YOUR CODE HERE
raise NotImplementedError()
# 使用不同场景测试推荐引擎:
print("场景 1 (预算50元 + 需要外卖):", recommend(restaurants, 50, {"delivery": True}))
print("场景 2 (预算100元 + 指定五道口商圈):", recommend(restaurants, 100, {"district": "五道口"}))
print("场景 3 (预算30元 + 要求校内就餐):", recommend(restaurants, 30, {"district": "清华校内"}, top_n=5))
assert callable(recommend)
result = recommend(restaurants, 50, {"delivery": True})
assert isinstance(result, list) and len(result) <= 3
assert all(isinstance(name, str) for name in result)
assert "紫光园(蓝旗营)" not in result, "紫光园不支持外卖,不应出现在场景 1 的结果中"
print("Q9 核心推荐引擎逻辑基础测试通过!")
恭喜你完成了本次数据分析与系统构建的挑战!通过这个项目,你已经将 Python 的基础语法成功应用到了实际的工程与业务场景中。
提交前的最终检查:
Kernel -> Restart & Run All,确保代码环境从头到尾运行顺畅且无报错。.ipynb 文件到课程平台。