python性能(4):Pandas和Geopandas读写大文件加速

在处理和分析大量大型的csv文件时(尤其是Geopandas)会遇到读写速度过慢的问题,因此一直想补充一个关于表格型文件读写步骤优化的讨论,此处对主要的结果进行了整理。

主要内容

数据的读写效率对实验的推进及迭代效率影响很大,针对大型数据已经开发了很多数据存储格式,尤其是Arrow存储的各种二进制文件如Apache Arrow平台的ORC 和 Parquet,这些格式读写远比csv、shp格式更为高效的数据格式。但是这两种格式在软件和处理的通用性、共享协作等方面根深蒂固,依旧较为流行,因此我们需要根据实际的需求及情况进行选择。此外,还有XML和JSON文件则广泛用于网页信息存储共享等,暂不列入本文的表格型数据讨论之内

实操建议:

  • 如果是小文件,或者需要考虑到不同用户之间的协作以及快速预览或制图等,建议用常规格式;
  • 若涉及较大数据处理、中间过程文件以及单个数据集的处理流程等,推荐使用二进制格式如Parquet和feather格式
  • 只考虑速度,使用——feather,兼顾存储空间和共享——Parquet
  • 对于Geopandas数据——强烈建议使用feather,中间的过程文件尤建议以Parquet/feather文件存储【QGIS可以直接查看feather文件】。读写速度差异见下文
  • 考虑到文件的大小,则优先使用Parquet,且使用列筛选 columns可以加速读取时间

pandas读写

参考:

  • 官方文档参考、公众号尤尔小屋
  • API:
    • pd.read_feather(),参数——columnsuse_threadsbool, 默认Ture-多线程
    • df.to_feature():参数——compression={“zstd”, “lz4”, “uncompressed”}, compression_level=None, chunksize=None...)
    • read_parquet()columns, engine={‘auto’, ‘pyarrow’, ‘fastparquet’},filters:[[(column, op, val), …],…],如‘[('adcode','>',410900)]等
    • to_parquet():partition_cols 列表,按列分区,compressionstr={‘snappy’, ‘gzip’, ‘brotli’, ‘lz4’, ‘zstd’, None}

结论:优先使用Parquet和feather,加速显著,此处我csv正常读写分别为2.5s和1min25s,feature则为0.7/1.6s,Parquet为1.5/2.1s,考虑到存储空间的问题,更推荐选Parquet

1
2
3
4
5
6
7
8
9
10

df = pd.read_csv("./data/pois.csv",encoding="utf-8",sep='\t')
df.info()

df.to_feather(outdir+"pois.feather")
df2 = pd.read_feather(outdir+"pois.feather")

df.to_parquet(outdir+"pois.parquet",index=False)
df2 = pd.read_parquet(outdir+"pois.parquet")
df2 = pd.read_parquet(outdir+"pois.parquet",columns=['adcode', 'pname', 'cityname'],filters=[('adcode','>',410900),('cityname','==','濮阳市')])

Geopandas读写

feather文件可以在qgis中直接打开查看

参考:geopandas官方文档参考

结论:优先使用feather,加速尤其显著,如果兼顾存储空间小使用Parquet(如此处读写一个200w行的poi shp文件分别需要4min和2min43s,改成feather是1.2s和4s,parquet则读写都是3s),完整的测试结果后续有时间补充。

1
2
3
4
5
6
7
8
9
10
11
# 数据测试
gdf = gpd.read_file("./data/pois.shp",encoding="utf-8")

gdf.to_parquet(outdir+"pois.parquet")
gdf2 = gpd.read_parquet(outdir+"pois.parquet")

gdf.to_feather(outdir+"pois.feather")
gdf2 = gpd.read_feather(outdir+"pois.feather")
# 只选取特定列也会显著加快速度
gdf2 = gpd.read_feather(outdir+"pois.feather",columns=['adname', 'cityname','geometry'])

实验补充

待续……