Python中Osmium读取OSM节点存入Pandas DataFrame遇报错及优化咨询
使用Osmium读取OSM节点存入DataFrame的问题解析
为什么存列表没问题,存DataFrame会报错?
Osmium的OSM对象(比如node、location)是临时生命周期:回调函数执行时才存在,执行完就会被底层内存管理回收。你存列表的时候,要是存的是node.id、node.location.lat这种基础数据类型(int、float),其实是把值拷贝到了列表里,没有持有原OSM对象的引用,所以没问题。
但如果存DataFrame时,你不小心直接把node对象、或者它的属性对象(比如node.location、node.tags)直接赋值给单元格,就会保留对这些临时OSM对象的引用——Osmium检测到这种情况就会抛出RuntimeError,防止内存泄漏或者野指针问题。
官方示例会出现这个问题吗?
不会。官方示例里是把节点的基础数值(id、纬度、经度)提取出来存入列表,完全没有保留原OSM对象的引用,所以不会触发报错。
列表和DataFrame存储的核心差异
本质不是列表和DataFrame的差异,而是你存储的内容是值还是对象引用:
- 列表如果存的是基础类型的值,和DataFrame存值的行为是一样的,都不会报错;
- 但如果存的是OSM对象的引用,不管是列表还是DataFrame,都会触发报错——只是很多人用列表时习惯存值,而用DataFrame时可能不小心直接存了对象(比如图省事写
df.append(node)),才会出现差异。
如何加快Osmium的读取过程?
- 只读取需要的实体类型:初始化Reader时指定只读取节点,跳过way、relation等不需要的内容,比如:
import osmium reader = osmium.Reader('your_file.osm', osmium.osm.osm_entity_bits.NODE) - 提前过滤节点:在回调函数里先判断节点是否符合你的需求(比如是否有特定tag、是否在指定坐标范围),不符合的直接跳过,减少后续处理的数据量;
- 批量写入DataFrame:不要逐行调用
df.append()(这是O(n²)复杂度,很慢),先把所有需要的节点数据收集到一个大列表里,最后一次性用pd.DataFrame(your_list, columns=['id', 'lat', 'lon'])转换,速度会快很多; - 用numpy数组暂存数据:如果数据量极大,用numpy数组存储id、lat、lon这些数值,再转成DataFrame,比纯列表的内存效率更高;
- 使用OSM二进制文件:如果可能,把.osm转成.osm.pbf二进制格式,Osmium读取二进制文件的速度比纯文本.osm快很多。
内容的提问来源于stack exchange,提问作者tribe
相关产品推荐
相关产品推荐

