温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!
一、 项目背景与意义
随着城市规模的不断扩大和公共交通网络的日益复杂,公交系统作为城市交通的“大动脉”,其运营效率和服务质量直接影响着市民的出行体验和城市的可持续发展。传统的公交客流分析多依赖于人工统计和报表,数据呈现方式单一,难以直观、动态地揭示客流在时间和空间上的分布规律与变化趋势。
本项目旨在设计并实现一个基于Python的某市公交线路客流可视化分析系统。其核心意义在于:
- 数据驱动决策:将海量的公交刷卡、GPS轨迹等原始数据转化为直观的图表和地图,为公交线路优化、班次调整、站点设置等运营决策提供数据支撑。
- 提升运营效率:通过识别高峰时段、高客流断面和低效线路,帮助管理者合理调配运力,减少空驶率,提升整体运营效率。
- 改善乘客体验:可视化分析有助于发现拥堵站点和换乘不便的节点,为改善候车环境、优化换乘指引提供依据。
- 技术实践价值:本项目综合运用了数据处理、空间分析、可视化等多种技术,是数据科学在智慧交通领域的典型应用,具有较高的学习和参考价值。
二、 技术栈选型
为实现高效的数据处理与丰富的可视化效果,本项目采用以下技术栈:
| 技术类别 | 具体技术/库 | 用途说明 |
|---|---|---|
| 数据处理与分析 | Pandas, NumPy | 核心数据分析库,用于数据清洗、聚合、转换和基础统计分析。 |
| 地理空间处理 | GeoPandas, Shapely | 处理公交线路、站点的地理空间数据(如GeoJSON),进行空间连接、缓冲区分析等。 |
| 数据可视化 | Matplotlib, Seaborn | 生成静态统计图表,如客流时序折线图、站点客流排行柱状图、热力图等。 |
| 交互式可视化 | Plotly, Folium | 创建可交互的图表和基于地图的可视化。Folium 特别适用于在地图上绘制公交线路和热力效果。 |
| Web应用框架 | Flask / Streamlit | 快速构建可视化分析系统的Web界面。Streamlit 更适合数据应用的快速原型开发。 |
| 开发环境与工具 | Jupyter Notebook, VS Code, Git | 用于代码开发、调试、实验和版本管理。 |
三、 系统核心模块与代码实现
系统主要分为数据预处理、客流指标计算、可视化呈现三大模块。以下是各模块的核心代码示例。
3.1 数据加载与预处理
假设原始数据包含公交刷卡记录表(`bus_records.csv`)和公交线路站点地理信息表(`bus_stops.geojson`)。
import pandas as pd import geopandas as gpd from datetime import datetime 1. 加载客流数据 def load_bus_data(record_path, stop_geo_path): """ 加载并初步处理公交数据。 """ # 读取刷卡记录 df_records = pd.read_csv(record_path, parse_dates=['transaction_time'], dtype={'line_id': str, 'stop_id': str}) # 读取站点地理信息 gdf_stops = gpd.read_file(stop_geo_path) # 数据清洗:处理缺失值、异常时间戳 df_records_clean = df_records.dropna(subset=['line_id', 'stop_id', 'transaction_time']) # 过滤掉未来时间或过早时间的记录(示例) current_year = datetime.now().year df_records_clean = df_records_clean[ df_records_clean['transaction_time'].dt.year.between(current_year-1, current_year) ] 衍生时间字段,便于按小时、工作日聚合 df_records_clean['hour'] = df_records_clean['transaction_time'].dt.hour df_records_clean['day_of_week'] = df_records_clean['transaction_time'].dt.dayofweek df_records_clean['date'] = df_records_clean['transaction_time'].dt.date return df_records_clean, gdf_stops 使用示例 df_records, gdf_stops = load_bus_data('data/bus_records.csv', 'data/bus_stops.geojson') print(f"客流记录数: {len(df_records)}") print(f"站点数: {len(gdf_stops)}")3.2 核心客流指标计算
class PassengerFlowAnalyzer: """ 客流分析核心类,计算各类指标。 """ def __init__(self, df_records, gdf_stops): self.df = df_records self.gdf_stops = gdf_stops def calculate_daily_flow(self): """计算每日总客流""" daily_flow = self.df.groupby('date').size().reset_index(name='passenger_count') return daily_flow def calculate_hourly_flow_by_line(self, line_id): """计算指定线路的小时级客流分布""" line_data = self.df[self.df['line_id'] == line_id] hourly_flow = line_data.groupby('hour').size().reset_index(name='count') return hourly_flow def calculate_top_stops(self, top_n=10): """计算客流最高的前N个站点""" stop_flow = self.df.groupby('stop_id').size().reset_index(name='passenger_count') # 关联地理信息 stop_flow_with_geo = stop_flow.merge( self.gdf_stops[['stop_id', 'stop_name', 'geometry']], on='stop_id', how='left' ) top_stops = stop_flow_with_geo.sort_values('passenger_count', ascending=False).head(top_n) return top_stops def calculate_section_flow(self, line_id): """ 计算线路断面客流(相邻站点间的客流量)。 简化逻辑:按时间顺序,乘客在站点i上车,在站点j下车。 此处假设通过连续刷卡记录推断。 """ # 示例逻辑:获取该线路所有记录,按卡号和时间排序,计算相邻站点的OD line_df = self.df[self.df['line_id'] == line_id].sort_values(['card_id', 'transaction_time']) line_df['next_stop'] = line_df.groupby('card_id')['stop_id'].shift(-1) # 过滤出有下一站的记录(即一次乘车的上车站) od_pairs = line_df.dropna(subset=['next_stop']) section_flow = od_pairs.groupby(['stop_id', 'next_stop']).size().reset_index(name='flow') return section_flow 使用示例 analyzer = PassengerFlowAnalyzer(df_records, gdf_stops) daily_flow = analyzer.calculate_daily_flow() top_10_stops = analyzer.calculate_top_stops(10) print(top_10_stops[['stop_name', 'passenger_count']].head())3.3 可视化模块示例
使用 Matplotlib 和 Folium 生成图表和地图。
import matplotlib.pyplot as plt import folium from folium.plugins import HeatMap def plot_daily_trend(daily_flow_df): """绘制日客流趋势折线图""" plt.figure(figsize=(12, 6)) plt.plot(daily_flow_df['date'], daily_flow_df['passenger_count'], marker='o', linewidth=2) plt.title('公交系统日客流趋势图', fontsize=15) plt.xlabel('日期') plt.ylabel('客流量(人次)') plt.grid(True, linestyle='--', alpha=0.7) plt.xticks(rotation=45) plt.tight_layout() plt.savefig('output/daily_trend.png', dpi=300) plt.show() def plot_top_stops_bar(top_stops_df): """绘制Top站点客流柱状图""" plt.figure(figsize=(10, 6)) plt.barh(top_stops_df['stop_name'][::-1], top_stops_df['passenger_count'][::-1]) plt.xlabel('客流量(人次)') plt.title('客流最高站点Top 10') plt.tight_layout() plt.savefig('output/top_stops.png', dpi=300) plt.show() def create_flow_heatmap(gdf_stops, df_records_sample): """ 在地图上创建客流热力图。 df_records_sample: 用于热力图的采样数据(需包含经纬度)。 """ # 获取城市中心坐标(示例) city_center = [gdf_stops.geometry.y.mean(), gdf_stops.geometry.x.mean()] m = folium.Map(location=city_center, zoom_start=12, tiles='CartoDB positron') # 准备热力图数据 [lat, lng, weight] heat_data = [] # 假设df_records_sample已通过站点ID关联了经纬度(lat, lng) for _, row in df_records_sample.iterrows(): heat_data.append([row['lat'], row['lng'], 1]) # weight可调整为客流量 添加热力图 HeatMap(heat_data, radius=15, blur=10, max_zoom=1).add_to(m) 可选:添加站点标记 for _, stop in gdf_stops.iterrows(): folium.CircleMarker( location=[stop.geometry.y, stop.geometry.x], radius=3, color='blue', fill=True, fill_opacity=0.6, popup=f"{stop['stop_name']} (ID: {stop['stop_id']})" ).add_to(m) m.save('output/passenger_heatmap.html') return m 生成图表 plot_daily_trend(daily_flow) plot_top_stops_bar(top_10_stops) 注意:需先准备包含经纬度的采样数据 df_records_sample heatmap_map = create_flow_heatmap(gdf_stops, df_records_sample)3.4 使用Streamlit构建简易Web应用
import streamlit as st import pandas as pd import plotly.express as px st.set_page_config(page_title="公交客流可视化分析", layout="wide") st.title("🚌 某市公交线路客流可视化分析系统") 侧边栏:数据与控制选项 st.sidebar.header("数据与控制") uploaded_file = st.sidebar.file_uploader("上传客流数据CSV", type=['csv']) line_list = ['1路', '2路', '3路', '5路', '10路'] # 示例线路列表 selected_line = st.sidebar.selectbox("选择分析线路", line_list) date_range = st.sidebar.date_input("选择日期范围", []) if uploaded_file is not None: df = pd.read_csv(uploaded_file) st.success(f"数据加载成功!共 {len(df)} 条记录。") # 选项卡布局 tab1, tab2, tab3 = st.tabs(["📈 趋势分析", "📍 站点排名", "🗺️ 空间分布"]) with tab1: st.subheader("日客流趋势") # 假设已计算 daily_flow_df fig_line = px.line(daily_flow, x='date', y='passenger_count', title=f"线路 {selected_line} 日客流趋势") st.plotly_chart(fig_line, use_container_width=True) with tab2: st.subheader("站点客流排名") # 假设已计算 top_stops_df fig_bar = px.bar(top_10_stops, x='passenger_count', y='stop_name', orientation='h', title="Top 10 客流站点") st.plotly_chart(fig_bar, use_container_width=True) with tab3: st.subheader("客流热力图") st.info("热力图功能需要地理坐标数据支持。") # 此处可嵌入Folium生成的HTML或使用Plotly地图 else: st.info("请通过侧边栏上传数据文件以开始分析。") st.markdown("---") st.caption("系统版本 1.0 | 基于 Python 构建")四、 总结与展望
本文设计并展示了基于Python的公交客流可视化分析系统的核心架构与代码。通过Pandas、GeoPandas进行数据处理,结合Matplotlib、Folium、Streamlit等库实现从静态图表到交互式地图、Web应用的全方位可视化。该系统能够将抽象的公交数据转化为直观的洞察,为公交运营优化提供有力工具。
未来可扩展方向:
- 实时数据接入:对接公交实时API,实现客流监控仪表盘。
- 预测模型集成:引入时间序列模型(如Prophet、LSTM)预测未来客流。
- 更精细的分析维度:结合天气、节假日、周边POI(兴趣点)数据进行多维关联分析。
- 性能优化:对于超大城市海量数据,考虑使用Dask进行并行计算,或利用PostGIS数据库进行空间查询加速。
本项目代码已模块化,读者可根据实际数据格式和需求进行调整与扩展,快速构建属于自己的交通数据分析应用。