地铁作为城市公共交通的主动脉,每天承载着数百万人的出行需求。如何从海量的刷卡记录中挖掘出有价值的客流规律,是城市智慧交通建设的关键课题。这次我们要搭建的Flask应用,正是基于Hive+Spark技术栈,实现对地铁客流数据的深度分析和可视化呈现,并引入线性回归模型进行客流预测。
这个项目的独特之处在于:
我们的技术栈采用分层架构设计:
code复制数据层:HDFS + Hive
计算层:Spark SQL + Spark MLlib
应用层:Flask + ECharts
这种组合的优势在于:
典型的数据处理流程如下:
地铁刷卡数据通常包含以下字段:
code复制card_id, station_id, timestamp, transaction_type
我们需要通过Spark SQL完成:
python复制# 计算各站点每小时客流量
df = spark.sql("""
SELECT
station_id,
hour(from_unixtime(timestamp)) as hour,
count(*) as passenger_count
FROM metro_transactions
GROUP BY station_id, hour(from_unixtime(timestamp))
""")
为线性回归模型准备特征时,我们考虑了:
python复制from pyspark.ml.feature import VectorAssembler
assembler = VectorAssembler(
inputCols=["hour", "is_weekend", "temperature"],
outputCol="features"
)
使用Spark MLlib实现线性回归:
python复制from pyspark.ml.regression import LinearRegression
lr = LinearRegression(
featuresCol="features",
labelCol="passenger_count",
maxIter=10,
regParam=0.3
)
model = lr.fit(train_data)
注意:实际应用中需要尝试不同的正则化参数和迭代次数,通过交叉验证选择最优参数
主要实现三个核心接口:
/api/stations - 获取站点列表/api/passenger_flow - 获取历史客流数据/api/predict - 获取预测结果python复制@app.route('/api/predict')
def get_prediction():
station_id = request.args.get('station')
# 调用Spark模型进行预测
result = predict_model(station_id)
return jsonify(result)
使用ECharts实现:
javascript复制// 初始化ECharts实例
var chart = echarts.init(document.getElementById('chart'));
// 设置热力图配置项
var option = {
tooltip: {...},
visualMap: {...},
series: [{
type: 'heatmap',
data: [...]
}]
};
chart.setOption(option);
python复制spark.conf.set("spark.sql.shuffle.partitions", "200")
python复制df.cache().count() # 触发缓存
python复制broadcast_var = spark.sparkContext.broadcast(station_info)
python复制from flask_caching import Cache
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app)
@app.route('/api/stations')
@cache.cached(timeout=3600)
def get_stations():
...
javascript复制// 使用Promise.all并行加载多个数据
Promise.all([
fetch('/api/stations'),
fetch('/api/passenger_flow')
]).then((responses) => {
// 处理数据
});
当某些站点客流量远大于其他站点时,会导致Spark任务执行缓慢。解决方案:
python复制from pyspark.sql.functions import rand
df.sampleBy("station_id", fractions={...}, seed=42)
python复制df = df.withColumn("salt", (rand() * 10).cast("int"))
当模型在训练集和测试集上表现都不理想时:
python复制assembler = VectorAssembler(
inputCols=["hour", "day_of_week", "is_holiday", ...],
outputCol="features"
)
python复制from pyspark.ml.feature import PolynomialExpansion
polyExpansion = PolynomialExpansion(
degree=2,
inputCol="features",
outputCol="polyFeatures"
)
推荐使用Docker容器化部署:
dockerfile复制FROM python:3.8
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-b :5000", "app:app"]
配合Nginx反向代理:
nginx复制server {
listen 80;
server_name metro-analysis.example.com;
location / {
proxy_pass http://localhost:5000;
}
}
python复制@app.route('/health')
def health_check():
return jsonify(status="healthy")
python复制from prometheus_flask_exporter import PrometheusMetrics
metrics = PrometheusMetrics(app)
metrics.info('app_info', 'Application info', version='1.0')
在实际应用中,这个项目还可以进一步扩展:
这个项目最让我有成就感的是,当看到预测曲线与实际客流高度吻合时,真切感受到了数据科学的魅力。建议初次尝试时可以先用小规模数据验证流程,再逐步扩展到全量数据。