1. 初识 aequilibrae:交通规划领域的瑞士军刀
第一次接触 aequilibrae 是在参与一个城市公交线网优化项目时。当时我们需要快速评估不同线路调整方案对整体交通流的影响,而传统商业软件不仅价格昂贵,操作流程还极其繁琐。直到团队里一位资深工程师推荐了这个开源工具,才真正体会到什么叫"专业工具干专业事"的效率提升。
aequilibrae 是一个基于 Python 的交通建模工具包,它的核心价值在于将学术级的交通分配算法工程化,让规划师和工程师能够通过简单的 Python 脚本完成复杂的交通网络分析。与 TransCAD 等商业软件相比,它最大的优势是开放的工作流——所有中间数据和计算过程都可控可调,这对于需要定制化分析的研究项目尤为重要。
提示:虽然 aequilibrae 的文档相对学术化,但实际使用时会发现它的 API 设计非常"Pythonic",特别是对已经熟悉 pandas 和 geopandas 的数据分析师来说,学习曲线其实相当平缓。
这个包的功能覆盖了交通规划的全流程:
- 网络构建:支持从 shapefile 或手动创建交通网络
- 矩阵处理:OD 矩阵的导入、转换和平衡处理
- 交通分配:实现用户均衡(UE)、系统最优(SO)等经典算法
- 结果分析:阻抗计算、流量统计和可视化输出
在最近的城市慢行交通规划项目中,我们仅用 50 行 Python 代码就完成了过去需要数天手工操作的分析流程,这让我深刻意识到开源工具正在改变交通规划行业的工作方式。
2. 环境配置与核心依赖解析
2.1 系统环境准备
aequilibrae 对 Python 环境的版本要求较为严格,经过多次实践验证,我推荐以下配置组合:
- Python 3.8/3.9(3.10+版本可能存在部分依赖兼容性问题)
- 64位操作系统(内存建议≥8GB,处理大型网络时需要更多)
创建专用虚拟环境是必须的,这能避免与现有环境中的库版本冲突:
bash复制conda create -n aeq_env python=3.9
conda activate aeq_env
2.2 核心依赖库说明
安装 aequilibrae 时会自动安装以下关键依赖:
- geopandas (≥0.10.0):处理空间数据的核心库
- numpy (≥1.21.0):矩阵运算基础
- scipy (≥1.7.0):优化算法实现
- pandas (≥1.3.0):数据表处理
- shapely (≥1.7.0):几何对象操作
特别要注意的是,geopandas 在 Windows 系统上可能安装失败,这时需要先安装其依赖:
bash复制conda install -c conda-forge gdal fiona pyproj rtree
2.3 安装验证与问题排查
完成基础安装后,建议运行以下验证脚本:
python复制import aequilibrae
print(aequilibrae.__version__) # 应输出类似 0.7.0 的版本号
from aequilibrae.project import Project
proj = Project()
print(proj.available_features()) # 检查核心功能是否可用
常见安装问题及解决方案:
- GDAL 相关错误:通常出现在 Windows 系统,建议通过 conda 而非 pip 安装地理相关库
- 库版本冲突:特别是 numpy 和 scipy 的版本,必要时可先卸载再指定版本安装
- 内存不足:处理大型网络时建议使用 Linux 系统或升级硬件配置
3. 项目创建与网络构建实战
3.1 初始化交通规划项目
aequilibrae 使用 SQLite 数据库存储所有项目数据,这种设计使得项目文件可以轻松共享和版本控制。新建项目的标准流程:
python复制from aequilibrae.project import Project
# 创建新项目
proj = Project()
proj.new('path/to/new_project.sqlite') # 会自动创建数据库文件
# 或者打开现有项目
proj = Project()
proj.open('path/to/existing_project.sqlite')
项目文件结构解析:
nodes:网络节点表(包含坐标等信息)links:路段属性表(方向、容量、阻抗等)zones:交通分区表matrices:OD 矩阵存储区results:计算结果的存储区域
3.2 网络数据导入与编辑
实际工作中,我们通常从 GIS 数据源导入基础路网。以下是典型的工作流:
python复制from aequilibrae.project import Network
# 初始化网络对象
net = proj.network
# 从shapefile导入路网
net.import_from_shapefile(
link_layer='path/to/roads.shp',
node_layer='path/to/nodes.shp',
link_fields={'link_id': 'id', 'direction': 'dir'}, # 字段映射
node_fields={'node_id': 'id'}
)
# 添加必要属性字段
net.links.add_fields(['capacity', 'free_flow_time'])
net.nodes.add_fields(['is_centroid'])
# 设置阻抗函数参数
for link in net.links.data:
link.free_flow_time = link.length / link.speed_limit # 计算自由流时间
link.capacity = 1000 # 设置默认容量
关键注意事项:
- 必须确保每个路段有明确的通行方向(单向或双向)
- 节点ID必须唯一且稳定,建议使用实际交叉口编号
- 阻抗函数参数应根据实际调查数据校准
3.3 交通分区与质心连接
交通分区(Traffic Zones)是需求分析的基础,其质心(Centroid)需要正确连接到路网:
python复制# 导入分区数据
proj.zones.import_from_shapefile('path/to/zones.shp', zone_id_field='zone_id')
# 标记质心节点
with proj.conn as conn:
conn.execute("UPDATE nodes SET is_centroid=1 WHERE node_id in (1001, 1002, 1003)")
# 创建虚拟连接线
net.build_centroid_connectors(
connector_specs={'walk': {'modes': 'c', 'capacity': 1e6}},
link_types={'walk': 'centroid_connector'}
)
这个步骤经常出现的问题是质心连接器阻抗设置不合理,导致交通分配结果异常。建议:
- 虚拟连接线的容量应设得足够大
- 步行模式通常用 'c' 表示(小汽车可及性)
- 连接长度不宜过长,一般控制在 500 米内
4. 交通分配算法深度解析
4.1 算法选择与参数配置
aequilibrae 实现了多种经典交通分配算法,最常用的是 Frank-Wolfe 系列的优化算法。以下是标准配置流程:
python复制from aequilibrae.paths import TrafficAssignment, TrafficClass
# 创建交通分配对象
assig = TrafficAssignment()
# 配置基础参数
assig.set_classes([TrafficClass(name='car', graph='graph_car')])
assig.set_vdf("BPR") # 使用BPR阻抗函数
assig.set_vdf_parameters({"alpha": 0.15, "beta": 4.0}) # BPR参数
assig.set_capacity_field("capacity") # 使用哪个字段作为容量
assig.set_time_field("free_flow_time") # 自由流时间字段
# 算法参数
assig.max_iter = 100 # 最大迭代次数
assig.rgap_target = 1e-6 # 相对差距阈值
assig.algorithm = 'bfw' # 使用Bi-conjugate Frank-Wolfe算法
不同算法的适用场景:
- fw (Frank-Wolfe):基础算法,适合小型网络
- bfw (Bi-conjugate FW):收敛更快,推荐用于中型网络
- msa (Method of Successive Averages):稳定性好,适合教学演示
4.2 OD 矩阵处理技巧
OD 矩阵是交通分配的核心输入,实际工作中常遇到矩阵不平衡的问题:
python复制from aequilibrae.matrix import AequilibraeMatrix
# 创建矩阵对象
demand = AequilibraeMatrix()
demand.create_empty(
file_path='demand.omx',
zones=len(proj.zones),
matrix_names=['car_demand']
)
# 从CSV导入数据
import pandas as pd
df = pd.read_csv('od_data.csv')
for _, row in df.iterrows():
demand.matrix['car_demand'][row.o, row.d] = row.trips
# 矩阵平衡处理
total_prod = demand.matrix['car_demand'].sum(axis=1)
total_attr = demand.matrix['car_demand'].sum(axis=0)
demand.balance_production(total_prod) # 按产生量平衡
实用技巧:
- 大型矩阵建议使用 OMX 格式存储,节省空间
- 平衡处理时应优先保证主要交通分区的准确性
- 可通过设置
compress=True减少内存占用
4.3 执行分配与结果解析
完成配置后,执行分配并分析结果:
python复制# 运行分配
assig.execute()
# 获取结果
results = assig.results()
link_flows = results.link_loadings # 路段流量
rgap_history = results.rgap_history # 收敛过程
# 保存结果到项目
proj.save()
# 可视化主要路段流量
import matplotlib.pyplot as plt
plt.plot(rgap_history)
plt.title('Algorithm Convergence')
plt.ylabel('Relative Gap')
plt.xlabel('Iteration')
plt.show()
结果分析要点:
- 检查相对间隙(RGAP)曲线是否平稳收敛
- 对比分配流量与实际观测值,校准参数
- 重点关注 V/C 比(流量/容量)大于 0.9 的路段
5. 实战案例:城市公交优先道评估
5.1 项目背景与数据准备
以某城市中心区公交专用道规划为例,我们需要评估三种方案:
- 现状方案(基线)
- 增设公交专用道
- 公交专用道+信号优先
数据准备:
- 路网 shapefile(含车道数、公交专用道标记)
- 现状 OD 矩阵(早高峰时段)
- 公交线路 GTFS 数据
python复制# 专用道设置函数
def set_priority_lanes(links, lane_type='bus'):
for link in links:
if link['priority'] == 1:
link['capacity_' + lane_type] = link['lanes'] * 800
link['fft_' + lane_type] = link['length'] / 30 # 公交专用速度
5.2 多模式网络配置
处理包含公交和小汽车的多模式网络:
python复制# 创建模式定义
proj.network.modes.add_mode('car', 'motorized')
proj.network.modes.add_mode('bus', 'public_transport')
# 设置路段模式可用性
for link in proj.network.links.data:
link.modes = 'car,bus' if link['lanes'] >= 2 else 'car'
# 创建公交线路
proj.transit.import_gtfs('path/to/gtfs.zip')
5.3 方案对比分析
执行三种场景的分配并对比结果:
python复制scenarios = ['baseline', 'priority_lane', 'priority_with_signal']
results = {}
for scen in scenarios:
if scen != 'baseline':
set_priority_lanes(proj.network.links.data, scen)
assig = TrafficAssignment()
# ...配置分配参数...
assig.execute()
results[scen] = {
'avg_travel_time': assig.results().average_travel_time,
'vmt': assig.results().total_vmt,
'bus_share': assig.results().class_results['bus'].share
}
# 生成对比报表
pd.DataFrame(results).T.plot(kind='bar', subplots=True)
关键发现:
- 公交专用道使公交行程时间降低 18%
- 组合方案进一步提升至 25% 改善
- 小汽车流量在专用道周边道路增加约 5%
6. 性能优化与高级技巧
6.1 大型网络处理策略
当处理城市级路网时(节点>10,000),需要特别考虑性能:
python复制# 内存优化配置
proj.parameters['memory_limit'] = '4GB' # 限制内存使用
# 并行计算设置
proj.parameters['number_of_processors'] = 4 # 使用4核
# 网络简化
proj.network.simplify(
remove_isolated=True, # 移除孤立节点
merge_short_links=50 # 合并短于50米的路段
)
6.2 自定义阻抗函数
标准 BPR 函数有时不能满足需求,可以自定义:
python复制def custom_vdf(flow, capacity, free_flow_time, **kwargs):
alpha = kwargs.get('alpha', 0.5)
beta = kwargs.get('beta', 2.5)
return free_flow_time * (1 + alpha * (flow / capacity)**beta)
assig.set_vdf(custom_vdf)
assig.set_vdf_parameters({'alpha': 0.3, 'beta': 3.0})
6.3 结果后处理方法
分配结果常需要进一步处理生成报告:
python复制# 路段级指标计算
links = proj.network.links.data
links['v_c_ratio'] = links['flow'] / links['capacity']
links['delay'] = links['travel_time'] - links['free_flow_time']
# 分区级统计
zonal_stats = proj.zones.copy()
zonal_stats['total_in'] = demand.matrix['car_demand'].sum(axis=0)
zonal_stats['total_out'] = demand.matrix['car_demand'].sum(axis=1)
# 生成GIS输出
links.to_file('output/flows.shp')
7. 常见问题排查指南
7.1 分配结果异常检查
当分配结果不符合预期时,按以下步骤排查:
-
检查网络连通性:
python复制from aequilibrae.paths import Graph g = Graph() g.prepare_graph(proj.network) print(g.check_connectivity()) -
验证阻抗参数:
- 确保自由流时间单位统一(通常为分钟)
- 检查 BPR 参数是否合理(典型值 alpha=0.15, beta=4)
-
OD 矩阵诊断:
- 检查矩阵总量是否合理
- 确认分区编号与网络一致
7.2 典型错误与解决方案
| 错误现象 | 可能原因 | 解决方案 |
|---|---|---|
| 分配流量全为零 | 网络与矩阵分区不匹配 | 检查 zone_id 对应关系 |
| 算法不收敛 | 阻抗参数不合理 | 调整 BPR 参数或尝试 msa 算法 |
| 内存溢出 | 网络规模太大 | 简化网络或增加内存限制 |
| 公交分配异常 | 模式定义错误 | 检查路段 mode 属性设置 |
7.3 调试技巧与日志分析
启用详细日志有助于定位问题:
python复制import logging
logging.basicConfig(level=logging.DEBUG)
# 在分配前添加
assig.set_logger(logging.getLogger('aequilibrae'))
关键日志信息解读:
RGAP not improving:可能需要调整算法参数Negative flow:通常表示网络方向设置有误Matrix not balanced:检查 OD 矩阵的生成过程
经过多个项目的实战检验,aequilibrae 已经成为了我处理交通规划问题的首选工具。虽然初期需要克服一些学习曲线,但一旦掌握其工作流程,就能以惊人的效率完成过去需要专业软件才能处理的分析任务。对于希望将交通建模工作流程自动化的团队,这个工具绝对值得投入时间学习。