智能旅行规划系统
一、项目前言
1.1 行业痛点
传统旅游规划依赖各类攻略平台,存在四大核心痛点:
- 全国景点数量庞大,人工筛选符合预算、评分的目的地效率极低;
- 多目的地自驾行程无法自动计算里程、时长、过路费,路线规划繁琐;
- 评分、票价、热度、地理位置数据分散,缺少统一可视化分析平台;
- 传统搜索仅关键词匹配,无法根据用户个性化偏好精准推荐景点。
1.2 项目概述
本项目名为途智・旅行规划师,基于纯 Python 开发,采用 Streamlit 快速搭建交互式 Web 平台,整合数据处理、多维可视化、机器学习混合推荐、DeepSeek RAG 智能问答、高德地图路线规划五大核心模块。系统面向普通游客、旅行规划者、旅游数据分析师三类用户,一站式实现景点浏览、个性化推荐、行程规划、数据洞察、AI 智能咨询全部功能。
1.3 整体技术栈
表格
| 分层 | 技术工具 | 核心作用 |
|---|---|---|
| Web 展示层 | Streamlit、自定义 CSS | 多页面路由、交互界面美化、组件渲染 |
| 数据处理层 | Pandas、NumPy、Scipy | CSV 数据清洗、特征构造、独立样本 T 检验 |
| 机器学习层 | Scikit-learn | KNN 相似推荐、KMeans 聚类、PCA 降维、标准化处理 |
| 可视化层 | PyEcharts | 11 种交互式图表,包含分布、排名、热力、散点、地图等 |
| AI 服务层 | DeepSeek API、自研三级检索 RAG | 景点 AI 介绍、旅游问答、知识库检索 |
| 地图服务层 | 高德 Web/JS API | 地理编码、驾车路径规划、交互式路线地图 |
二、系统整体架构与页面设计
2.1 三层解耦架构
系统采用分层低耦合设计,分为数据层、服务层、展示层,模块职责清晰,便于维护迭代:
- 数据层 DataManager:统一加载清洗景点 CSV,构造衍生特征,构建省 - 区县三级树形数据,全局单例缓存数据集;
- 服务层(四大独立 Service)
- RecommendService:偏好推荐、KNN 相似推荐、KMeans 聚类、混合加权推荐;
- VisualizationService:封装全部可视化图表,支持省 / 区县数据联动筛选;
- AIService:本地知识库构建、三级检索 RAG、DeepSeek 对话、多级降级容错;
- MapService:地址转经纬度、驾车路线计算、地图 HTML 文件生成;
- 展示层 Streamlit UI:四页面导航、侧边联动筛选、分页列表、路线管理、AI 聊天窗口。
2.2 数据流逻辑
原始景点 CSV 数据集 → DataManager 清洗并构造特征矩阵 → 四大服务读取处理数据 → Streamlit 页面渲染图表、推荐列表、地图、AI 对话内容
2.3 四大功能页面划分
- 景点浏览页:省区县联动筛选、分页景点卡片、景点 AI 详情、自驾路线规划、RAG 聊天助手;
- 数据可视化页:4 个子标签,11 类交互式图表,完成数据分布、区域对比、空间热力分析;
- 智能推荐页:偏好筛选推荐、KNN 相似景点检索、KMeans 聚类分析 + PCA 降维散点图;
- 数据分析页:描述性统计、特征相关性矩阵、5A / 非 5A 景点 T 检验、聚类模型指标评估。
2.4 整体页面布局设计
系统统一布局结构:顶部标题栏 + 横向导航栏 + 左侧筛选侧边栏 + 主体内容区,景点 / 推荐页面采用左右双栏(主内容 + 详情面板),可视化、数据分析页面采用全屏布局。

三、数据集预处理模块
3.1 数据集基础信息
数据源为结构化景点数据.csv,共 13617 条完整有效数据。 原始核心字段:序号、景点名称、综合评分、景区等级、门票价格、销量热度、省份、完整区域、详细地址、景点简介。 衍生字段:
heat_score综合热度:平衡评分与人气,计算公式:\(heat\_score=score×0.4 + (sales/max\_sales)×0.6\);district区县字段:从 region 字符串切割提取末级区县名称;- 6 维机器学习特征:原始评分、归一化价格、对数销量、综合热度、编码景区等级、归一化省份编码。
3.2 数据清洗核心代码(data_manager.py)
仅过滤名称、评分、价格、销量为空的无效数据,价格为 0 代表免费景点,予以保留;同时完成热度特征、区县字段构造。
python
运行
def load_data(self):
if not os.path.exists(DATA_FILE):
raise FileNotFoundError(f"数据文件不存在: {DATA_FILE}")
self.df = pd.read_csv(DATA_FILE)
# 过滤关键字段空值
self.df = self.df[self.df['name'].notna()]
self.df = self.df[self.df['score'].notna()]
self.df = self.df[self.df['price'].notna()]
self.df = self.df[self.df['sales'].notna()]
self.df = self.df.reset_index(drop=True)
# 构造综合热度指标
max_sales = self.df['sales'].max()
self.df['heat_score'] = self.df['score'] * 0.4 + (self.df['sales'] / max_sales) * 0.6
# 提取区县名称
self.df['district'] = self.df['region'].apply(
lambda x: x.split('-')[-1 if isinstance(x, str) and '-' in x else x
)
print(f"[OK] 数据加载成功: {len(self.df)} 条记录")
清洗前后对比统计表:
|
指标 |
清洗前 |
清洗后 |
|
记录总数 |
13617 |
13617 |
|
score 有效记录数 |
13617 |
13617 |
|
price 有效记录数 |
13617 |
13617 |
|
sales 有效记录数 |
13617 |
13617 |
3.3 特征标准化处理
对 6 维特征做编码、归一化、Z-score 标准化,消除量纲差异,保证模型距离计算准确。
def _build_features(self):
le = LabelEncoder()
level_encoded = le.fit_transform(df['level'].fillna('未评级'))
province_le = LabelEncoder()
province_encoded = province_le.fit_transform(df['province'])
# 拼接6维原始特征
features = np.column_stack([
df['score'].values, df['price']/100, np.log1p(df['sales'])/10,
df['heat_score'].values, level_encoded, province_encoded/32.0
])
self.scaler = StandardScaler()
self.feature_matrix = self.scaler.fit_transform(features)
标准化前后特征统计对比表格:
|
特征 |
标准化前均值 |
标准化后均值 |
标准化前 std |
标准化后 std |
|
score (评分) |
7.6583 |
-0.000000000 |
0.95552 |
1.00003672 |
|
price/100 (价格) |
0.76887 |
0.000000000 |
1.7334 |
1.00003672 |
|
log (sales+1)/10 (销量) |
0.29999 |
-0.000000000 |
0.22779 |
1.00003672 |
|
heat_score (热度) |
3.06556 |
0.000000000 |
0.3844 |
1.00003672 |
|
level_enc (等级) |
2.53888 |
-0.000000000 |
0.9323 |
1.00003672 |
|
province_enc/32 (省份) |
0.48008 |
0.000000000 |
0.2866 |
1.00003672 |
3.4 省 - 区县三级层级构建
构建字典层级结构hierarchy={省份:{区县:[景点列表]}},每个区县内景点按综合热度降序排列,供侧边筛选、页面列表快速读取。
def build_hierarchy(self):
self.hierarchy = {}
for _, row in self.df.iterrows():
province = row['province']
district = row['district']
scenic = row.to_dict()
if province not in self.hierarchy:
self.hierarchy[province] = {}
if district not in self.hierarchy[province]:
self.hierarchy[province][district] = []
self.hierarchy[province][district].append(scenic)
# 区县内按热度降序
for p in self.hierarchy:
for d in self.hierarchy[p]:
self.hierarchy[p][d].sort(key=lambda x:x["heat_score"], reverse=True)
四、机器学习推荐模型实现
4.1 KNN 余弦相似度相似推荐
以标准化 6 维特征向量计算余弦相似度,匹配风格近似景点,适合用户输入单一景点查找同类目的地。
# 模型初始化
self.knn_model = NearestNeighbors(n_neighbors=20, metric='cosine', algorithm='brute')
self.knn_model.fit(self.feature_matrix)
def knn_recommend(self, scenic_name: str, top_k: int = 10) -> List[Dict]:
idx = self.df[self.df['name'].str.contains(scenic_name, na=False)].index[0]
query_vec = self.feature_matrix[idx].reshape(1, -1)
distances, indices = self.knn_model.kneighbors(query_vec)
results = []
for i, dist in zip(indices[0], distances[0]):
if i == idx: continue
scenic = self.df.iloc[i].to_dict()
scenic['similarity'] = round(1 - dist, 4)
results.append(scenic)
return results[:top_k]
4.2 KMeans 聚类模型
自动适配聚类数量,固定随机种子保证实验可复现,同簇景点特征相近,用于聚类分组推荐。
n_clusters = min(8, len(self.df) // 500)
self.cluster_model = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
self.cluster_labels = self.cluster_model.fit_predict(self.feature_matrix)
self.df['cluster'] = self.cluster_labels
def cluster_recommend(self, scenic_name: str, top_k: int = 10) -> List[Dict]:
idx = self.df[self.df['name'].str.contains(scenic_name)].index[0]
cluster_id = self.cluster_labels[idx]
same_cluster = self.df[self.cluster_labels == cluster_id]
# 同簇内计算相似度排序
...
4.3 混合加权推荐(项目创新点)
融合 KNN 全局相似度(权重 0.6)、KMeans 同簇相似度(权重 0.4),合并去重后加权排序,兼顾全局风格与同类特征,解决单一算法局限性。
def hybrid_recommend(self, scenic_name: str, top_k: int = 12) -> List[Dict]:
knn_results = self.knn_recommend(scenic_name, top_k * 2)
cluster_results = self.cluster_recommend(scenic_name, top_k * 2)
seen = set()
merged = []
# KNN加权入库
for r in knn_results:
if r['name'] not in seen:
r['weight'] = 0.6 * r.get('similarity', 0.5)
seen.add(r['name'])
merged.append(r)
# 聚类加权入库
for r in cluster_results:
if r['name'] not in seen:
r['weight'] = 0.4 * r.get('similarity', 0.5)
seen.add(r['name'])
merged.append(r)
merged.sort(key=lambda x: x.get('weight', 0), reverse=True)
return merged[:top_k]
4.4 基于用户偏好内容推荐
通过滑块限定最低评分、最高票价、免费筛选,自定义推荐分数,优先推荐高性价比景点。
def content_recommend(self, preferences: Dict, top_k: int = 10, province=None, district=None):
df = self.df.copy()
# 地域筛选
if province:
df = df[df['province'] == province]
if district: df = df[df['district'] == district]
# 用户偏好过滤
min_score = preferences.get('min_score')
max_price = preferences.get('max_price')
free_only = preferences.get('free_only')
df = df[df['score'] >= min_score]
df = df[df['price'] <= max_price]
if free_only: df = df[df['price'] == 0]
# 综合推荐打分
df['rec_score'] = (df['score']/10)*0.45 + (df['sales']/df['sales'].max())*0.25 + (1/(df['price']+1))*0.15
return df.nlargest(top_k, 'rec_score').to_dict('records')
五、多维可视化模块(VisualizationService)
基于 PyEcharts 实现 11 类交互式图表,全部封装为统一方法,支持省份、区县筛选过滤,统一返回 HTML 字符串嵌入页面。以评分分布直方图、全国热力地图为例:
5.1 景点评分分布直方图
def score_distribution(self, province: str = None, district: str = None) -> str:
df = self._filter_df(province, district)
scores = df['score'].dropna()
bins = 20
hist, bin_edges = np.histogram(scores, bins=bins)
bar = Bar(init_opts=opts.InitOpts(width="100%", height="460px"))
bar.add_xaxis([f"{bin_edges[i]:.1f}" for i in range(len(bin_edges)-1)])
bar.add_yaxis("景点数量", hist.tolist(), itemstyle_opts=opts.ItemStyleOpts(...))
bar.set_global_opts(title_opts=opts.TitleOpts(title=f"{province or '全国'}景点评分分布", ...))
return self._wrap_chart(bar.render_embed(), 480)
5.2 全国省份景点热力地图
def china_heatmap(self) -> str:
province_counts = self.df['province'].value_counts()
data_pair = [(k, int(v)) for k, v in province_counts.items()]
map_chart = Map(init_opts=opts.InitOpts(width="100%", height="500px"))
map_chart.add("景点数量", data_pair, "china", is_map_symbol_show=False)
map_chart.set_global_opts(visualmap_opts=opts.VisualMapOpts(range_color=[...]))
return self._wrap_chart(map_chart.render_embed(), 520)
完整图表清单:评分直方图、价格玫瑰饼图、等级玫瑰图、免费景点仪表盘、省份柱状排名、区县柱状排名、热度 Top20 柱状图、评分 - 价格散点图、省份雷达对比、均价双柱图、评分箱型图、全国热力地图。











六、DeepSeek RAG 智能问答模块
6.1 三级本地检索策略
无需向量数据库,基于本地景点索引低成本检索,杜绝大模型凭空编造信息:
- 一级精确匹配:用户输入包含完整景点名,直接调取景点全部数据;
- 二级省份匹配:识别省份关键词,调取该省均分、均价、热门景点统计;
- 三级模糊关键词匹配:拆分关键词模糊检索景点名称补充候选数据。
def _search_knowledge(self, query: str, top_k: int = 5) -> List[Dict]:
matched = []
# 1.精确景点匹配
for name in self.scenic_index:
if name in query:
matched.append(self.scenic_index[name])
# 2.省份匹配
for p in self.data_manager.get_provinces():
if p in query and len(p) > 1:
matched.append({"type":"province_stats", "province":p, "stats":self.province_stats[p]})
# 3.关键词模糊检索
if len(matched) < top_k:
keyword_list = query.replace("推荐","").replace("好玩","").split()
for kw in keyword_list:
if len(kw)>=2:
sub_df = self.data_manager.df[self.data_manager.df['name'].str.contains(kw)].head(top_k)
for _,row in sub_df.iterrows(): matched.append(row.to_dict())
return matched[:top_k]
6.2 四级降级容错对话架构
系统可用性保障,分层降级避免 API 失效导致功能崩溃:本地规则匹配→RAG 检索增强→DeepSeek API 生成→纯本地文本兜底。
def chat(self, user_message: str, context: Dict = None) -> str:
# 第一层:本地规则直接回复
local_response = self._local_response(user_message)
if local_response: return local_response
# 第二层:RAG检索本地知识库上下文
rag_context = self._build_rag_context(user_message, context)
# 第三层:调用DeepSeek大模型API
if self.client:
try:
system_prompt = f"""你是旅游助手途智,仅依据下方景点数据回答,禁止编造景点信息。{rag_context}"""
response = self.client.chat.completions.create(
model="deepseek-chat",
messages=[{"role":"system","content":system_prompt},{"role":"user","content":user_message}],
temperature=0.7, max_tokens=800
)
return response.choices[0].message.content
except Exception:
pass
# 第四层:API故障,仅返回检索到的本地数据兜底
if rag_context:
return f"检索到相关景点数据:{rag_context[:500]}"
return "你可以询问省份、景点名称获取旅游推荐"

6.3 景点 AI 详情生成
输入景点原始数据,由 DeepSeek 生成 200 字左右专业景点介绍,API 失效时自动使用模板拼接基础信息兜底。
def analyze_scenic(self, scenic_name: str) -> Dict:
scenic = self.data_manager.get_scenic_by_name(scenic_name)
result = {"name":scenic['name'],"score":scenic['score'],"price":scenic['price'],...}
if self.client:
prompt = f"基于以下信息写200字景点介绍:名称{scenic['name']},等级{scenic['level']},评分{scenic['score']},简介{scenic['comments']}"
resp = self.client.chat.completions.create(model="deepseek-chat", messages=[...])
result['ai_intro'] = resp.choices[0].message.content
else:
# 本地模板兜底生成简介
...
return result

七、高德地图路线规划模块
封装高德 Web、JS 双 API,实现地址解析、多途经点路线计算、交互式路线地图生成,完整行程可视化。
7.1 地理编码(地址转经纬度)
def geocode(address: str, city: str = "") -> Optional[Dict]:
url = "https://restapi.amap.com/v3/geocode/geo"
params = {"key": AMAP_WEB_API_KEY, "address": address, "city": city, "output":"JSON"}
resp = requests.get(url, timeout=10)
data = resp.json()
if data["status"] == "1" and data["geocodes"]:
lng, lat = data["geocodes"][0]["location"].split(",")
return {"lng":float(lng), "lat":float(lat)}
return None
7.2 多途经点驾车路线计算
支持最多 16 个途经景点,返回总里程、耗时、过路费、路线坐标串 polyline。
def route_planning(origin, destination, waypoints=None, strategy=0):
url = "https://restapi.amap.com/v3/direction/driving"
params = {"key":AMAP_WEB_API_KEY,"origin":f"{origin[0]},{origin[1]}","destination":f"{destination[0]},{destination[1]}","strategy":0}
if waypoints:
wp_str = ";".join([f"{wp[0]},{wp[1]}" for wp in waypoints[:16]])
params["waypoints"] = wp_str
resp = requests.get(url)
data = resp.json()
if data["status"] == "1":
path = data["route"]["paths"][0]
return {
"distance": int(path["distance"]), "duration": int(path["duration"]),
"tolls": int(path["tolls"]), "polyline": path["polyline"], "steps": path["steps"]
}
return None
7.3 交互式路线地图 HTML 生成
拼接高德 JS API 模板,生成带点位标记、行车路线、信息弹窗的独立 HTML 文件,在页面内嵌展示。
def generate_route_map_html(scenics: List[Dict], route_info: Dict = None) -> str:
# 提取所有景点坐标,计算地图中心点
lngs, lats = [], []
for s in scenics:
loc = s.get("location", "").split(",")
lngs.append(float(loc[0])), lats.append(float(loc[1]))
center = [sum(lngs)/len(lngs), sum(lats)/len(lats)]
# 拼接前端HTML模板,注入路线、点位JSON
html_template = f"""<!DOCTYPE html><html><head><script src="https://webapi.amap.com/maps?v=2.0&key={AMAP_JS_API_KEY}"></script>
<body><div id="container"></div>
<script>var markers = {json.dumps(markers)}; var routeData = {json.dumps(route_info)}; ... </script>
</body></html>"""
map_path = os.path.join(OUTPUT_DIR, "map_route.html")
with open(map_path, "w", encoding="utf-8") as f:
f.write(html_template)
return map_path

八、Streamlit 主程序页面实现(app.py)
8.1 全局基础配置
必须放在所有 Streamlit 组件最前端,配置页面标题、图标、宽屏布局、侧边默认展开。
# 项目路径导入
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
sys.path.append("E:\\daima")
import streamlit as st
# 全局页面配置(首行组件)
st.set_page_config(
page_title="途 · 旅行规划师",
page_icon="⛰️",
layout="wide",
initial_sidebar_state="expanded"
)
8.2 服务与会话状态缓存
使用@st.cache_resource全局缓存 AI、可视化、推荐服务,避免页面刷新重复初始化;session_state 持久保存筛选、对话、路线、页码状态。
@st.cache_resource
def get_services():
ai_svc = DeepSeekService(data_manager)
viz_svc = VisualizationService(data_manager)
rec_svc = RecommendService(data_manager)
return ai_svc, viz_svc, rec_svc
def init_session_state():
# 筛选状态
if "selected_province" not in st.session_state: st.session_state.selected_province = ""
if "selected_district" not in st.session_state: st.session_state.selected_district = ""
# 服务实例
if "ai_service" not in st.session_state:
st.session_state.ai_service, st.session_state.viz_service, st.session_state.rec_service = get_services()
# 对话、分页、路线、页面路由
if "chat_messages" not in st.session_state: st.session_state.chat_messages = []
if "page_num" not in st.session_state: st.session_state.page_num = 0
if "current_page" not in st.session_state: st.session_state.current_page = "景点浏览"
if "route_scenics" not in st.session_state: st.session_state.route_scenics = []
init_session_state()
8.3 全局自定义 CSS 美化
覆盖原生 Streamlit 简陋样式,定义头部渐变、景点卡片、聊天气泡、统计网格统一样式。
def load_css():
st.markdown("""
<style>
.main-header {
background: linear-gradient(135deg, #1a237e, #283593);
padding: 14px 24px; border-radius: 8px; color: white;
display: flex; justify-content: space-between; align-items: center;
}
.scenic-list-item { background: #f8f9fa; border-radius: 6px; padding: 12px; margin:8px 0; }
.chat-msg-user { background:#e8f0fe; padding:8px; border-radius:6px; margin:4px 0;}
.chat-msg-ai { background:#f1f3f4; padding:8px; border-radius:6px; margin:4px 0;}
...
</style>
""", unsafe_allow_html=True)
8.4 顶部标题栏渲染
展示系统名称、实时日期、全局景点 / 省份统计数量。
def render_header():
import pandas as pd
st.markdown(f"""
<div class="main-header">
<div>
<h1><span class="highlight">途智</span> · 旅行规划师</h1>
<div class="subtitle">基于多源数据、机器学习与地图API智能分析系统</div>
</div>
<div style="text-align:right;">
<div style="color:#ffd54f;">{pd.Timestamp.now().strftime('%Y年%m月%d日')}</div>
<div>景点{len(data_manager.df)} | 省份{len(data_manager.get_provinces())}</div>
</div>
</div>
""", unsafe_allow_html=True)
8.5 侧边栏省区县联动筛选
省份切换自动清空区县、重置分页,实现二级联动下拉框。
def _on_prov_change():
prov = st.session_state.get("sidebar_prov", "")
if prov == "全部": prov = ""
if prov != st.session_state.selected_province:
st.session_state.selected_province = prov
st.session_state.selected_district = ""
st.session_state.page_num = 0
def render_sidebar():
with st.sidebar:
st.markdown("""<div style="text-align:center;"><h2>🗺️途智规划师</h2></div>""", unsafe_allow_html=True)
st.divider()
# 省份下拉
provinces = ["全部"] + data_manager.get_provinces()
st.selectbox("📍省份", provinces, index=..., key="sidebar_prov", on_change=_on_prov_change)
# 选中省份后展示区县下拉
if st.session_state.selected_province:
districts = ["全部"] + data_manager.get_districts(st.session_state.selected_province)
st.selectbox("📍区县", districts, index=..., key="sidebar_dist", on_change=_on_dist_change)
st.divider()
# 路线列表、景点搜索...
8.6 顶部导航与页面路由分发
横向四按钮导航,点击切换页面,路由分发渲染对应页面内容。
def main():
load_css()
render_header()
# 顶部导航
current = st.session_state.current_page
pages = ["🏯 景点浏览", "📊 数据可视化", "🤖 智能推荐", "📈 数据分析"]
cols = st.columns(len(pages))
for idx, page in enumerate(pages):
with cols[idx]:
clean_name = page.split(" ",1)[1]
is_active = current == clean_name
if st.button(page, use_container_width=True, type="primary" if is_active else "secondary"):
st.session_state.current_page = clean_name
st.rerun()
st.divider()
# 页面路由
if current == "景点浏览":
col_main, col_right = st.columns([2.2, 1])
with col_main: page_scenic_browse(); render_chat()
with col_right: render_detail_panel()
elif current == "数据可视化":
page_visualization()
elif current == "智能推荐":
...
render_sidebar()
if __name__ == "__main__":
main()
九、项目创新点、不足与优化方向
9.1 核心创新亮点
- 混合加权推荐算法:融合 KNN 全局相似度、KMeans 聚类相似度,平衡全局风格与同类特征,提升推荐匹配度;
- 轻量化 RAG 本地检索:不依赖向量数据库,三级关键词检索低成本消除大模型幻觉,数据全部来自本地景点库;
- 地图与推荐深度联动:任意推荐景点可一键加入路线,批量生成多目的地自驾路线地图;
- 多级容错降级架构:AI、地图 API 异常均有本地兜底逻辑,系统不会崩溃;
- 一站式全链路 Python 项目:无需前端、后端分离,单语言完成数据处理、机器学习、可视化、GIS 地图、大模型集成。
9.2 现存不足
- 数据存储:当前采用内存 CSV 存储,百万级大数据加载缓慢;
- 推荐维度:仅使用数值特征,未引入景点文本评论 TF-IDF 语义特征;
- 路线功能:仅支持自驾,缺少公交、高铁规划;
- AI 能力:无 Agent 工具调用,无法自主查询、计算数据。
9.3 后续拓展优化方案
- 存储优化:迁移 SQLite/MySQL 数据库,实现分块读取、条件查询;
- 算法升级:新增协同过滤、XGBoost 打分,引入用户收藏行为;
- 功能拓展:接入天气、酒店、餐饮 API,完善出行配套信息;
- AI 升级:接入 FAISS 向量库实现语义检索,增加工具调用 Agent;
- 性能优化:图表、推荐结果增加缓存,异步请求外部 API。
十、项目部署运行说明
10.1 依赖安装命令
pip install streamlit pandas numpy scikit-learn pyecharts scipy requests openai
10.2 完整项目目录结构
project/
├── app.py # 主程序入口
├── config.py # API密钥、文件路径配置
├── data_manager.py # 数据加载、清洗、特征构造
├── recommend_service.py # 四大推荐算法
├── visualization_service.py # 全部可视化图表
├── ai_service.py # DeepSeek RAG问答
├── map_service.py # 高德地图接口封装
├── ui_components.py # 复用UI组件
├── data/
└── 景点数据.csv # 原始数据集
└── output/ # 运行生成地图HTML文件
10.3 项目启动命令
streamlit run app.py
十一、总结
本项目完整覆盖数据清洗→特征工程→机器学习建模→交互式可视化→RAG 大模型应用→GIS 地图开发→Web 系统搭建全数据科学开发流程,面向旅游行业真实业务场景,功能完整、模块化清晰,非常适合大数据、计算机专业实训、课程设计、毕业设计作业参考。系统全部基于 Python 实现,无需前端开发基础,一条命令即可运行完整可交互 Web 平台,兼具数据分析学术价值与真实落地使用价值。
以下为作品界面和部分功能展示:
途智 · 旅行规划师演示
更多推荐



所有评论(0)