(數據科學學習手札77)基於geopandas的空間數據分析——文件IO


本文對應代碼和數據已上傳至我的Github倉庫https://github.com/CNFeffery/DataScienceStudyNotes

1 簡介

  在上一篇文章中我們對geopandas中的坐標參考系有了較為深入的學習,而在日常空間數據分析工作中矢量文件的讀入和寫出,是至關重要的環節。

  作為基於geopandas的空間數據分析系列文章的第三篇,通過本文你將會學習到geopandas中的文件IO

2 文件IO

2.1 矢量文件的讀入

  geopandasfiona作為操縱矢量數據讀寫功能的后端,使用geopandas.read_file()讀取對應類型文件,而在后端實際上是使用fiona.open來讀入數據,即兩者參數是保持一致的,讀入的數據自動轉換為GeoDataFrame,下面是geopandas.read_file()主要參數:

filename:str類型,傳入文件對應的路徑或url
layer:str類型,當要讀入的數據格式為地理數據庫.gdbQGIS中的.gpkg時,傳入對應圖層的名稱

  下面結合上述參數,來介紹一下使用geopandas.read_file()在不同情況下讀取常見格式矢量數據的方法,使用到的示例數據為中國地圖,CRSEPSG:4326,本文使用到的所有數據都可以在文章開頭提及的Github倉庫對應本文路徑下找到:

圖1

2.1.1 shapefile

  作為非常常見的一種矢量文件格式,geopandasshapefile提供了很好的讀取和寫出支持,下面分為不同情況來介紹:

  • 完整的shapefile

  如圖2,這是一個完整的shapefile

圖2

  使用geopandas來讀取這種形式的shapefile很簡單:

import geopandas as gpd

data = gpd.read_file('geometry/china_provinces/china_provinces.shp')
print(data.crs) # 查看數據對應的crs
data.head() # 查看前5行
圖3
  • 缺少投影的shapefile

  當shapefile中缺失.prj文件時,使用geopandas讀入后形成的GeoDataFrame會缺失crs屬性:
  

圖4

  如果已經知道數據對應的CRS,可以在讀入數據后補充上crs信息以進行其他操作:

import pyproj

data.crs = pyproj.CRS.from_user_input('EPSG:4326')
data.crs
圖5
  • 直接讀取文件夾

  當文件夾下只有單個shapefile時,可以直接讀取該文件夾:

圖6
  • 讀取zip壓縮包中的文件

  geopandas通過傳入特定語法格式的文件路徑信息,以支持直接讀取.zip格式壓縮包中的shapefile文件,主要分為兩種情況。
  當文件在壓縮包內的根目錄時,使用下面的語法規則來讀取數據:

zip://路徑/xxx.zip

  譬如我們要讀取圖7所示的壓縮包內文件:

圖7

  按照對應的語法規則,讀取該類型數據方式如下:

圖8

  而當文件在壓縮包內的文件夾中時,如圖9:
  

圖9

  使用下面的語法規則來讀取數據:

zip://路徑/xxx.zip!壓縮包內指定文件路徑

  將上述語法運用到上述文件:

圖10

2.1.2 gdb與gpkg

  對於Arcgis中的地理數據庫gdb,以及QGIS中的GeoPackage,要讀取其包含的矢量數據,就要涉及到圖層的概念,對應geopandas.read_file()layer參數,只需要將gdbgpkg文件路徑作為filename參數,再將對應的圖層名稱作為layer參數傳入:

  • gdb
data = gpd.read_file('geometry/china_provinces.gdb', 
                     layer='china_provinces')
print(data.crs) # 查看數據對應的crs
data.head() # 查看前5行
圖11
  • gpkg

  類似讀入gdb文件:

data = gpd.read_file('geometry/china_provinces.gpkg', 
                     layer='china_provinces',
                     encoding='utf-8')
print(data.crs) # 查看數據對應的crs
data.head() # 查看前5行
圖12

2.1.3 GeoJSON

  作為web地圖中最常使用的矢量數據格式,GeoJSON幾乎被所有在線地圖框架作為數據源格式,在geopandas中讀取GeoJSON非常簡單,只需要傳入文件路徑名稱即可,下面我們來讀入圖13所示的文件:

圖13
圖14

2.1.4 過濾

  geopandas在0.1.0版本中新增了bbox過濾,在0.7.0版本中新增了蒙版過濾行過濾功能,可以輔助我們根據自己的需要讀入原始數據中的子集,下面一一進行介紹:

  • bbox過濾

  bbox過濾允許我們在read_file()中傳入一個邊界框作為參數bbox,格式為(左下角x, 左下角y, 右上角x, 右上角y),這樣在讀入的過程中只會保留幾何對象與bbox有相交的數據記錄,下面我們仍然以上文中使用過的中國地圖數據為例,我們在讀入的過程中,傳入邊界框:

from shapely import geometry

data = gpd.read_file('geometry/china_provinces.json',
                    bbox=(100, 20, 110, 30))

%matplotlib widget
ax = data.plot()
# 繪制bbox框示意
ax = gpd.GeoSeries([geometry.box(minx=100, 
                                 miny=20, 
                                 maxx=110, 
                                 maxy=30).boundary]).plot(ax=ax, color='red')
圖15

  可以看到只有跟紅色框有相交的幾何對象被讀入。

  • 蒙版過濾

  蒙版過濾bbox過濾功能相似,都是篩選與指定區域相交的數據記錄,不同的是蒙版過濾通過mask參數可以傳入任意形狀的多邊形,不再像bbox過濾那樣只接受矩形:

data = gpd.read_file('geometry/china_provinces.json',
                    mask=geometry.Polygon([(100, 20), (110, 30), (120, 20)]))

ax = data.plot()
# 繪制bbox框示意
ax = gpd.GeoSeries([geometry.Polygon([(100, 20), 
                                      (110, 30), 
                                      (120, 20)]).boundary]).plot(ax=ax, color='red')
圖16

  可以看到只有跟紅色多邊形相交的幾何對象被讀入。

  • 行過濾

  行過濾的功能就比較簡單,通過參數rows控制讀入原數據的前若干行,可以用於在讀取大型數據時先快速查看前幾行以了解整個數據的格式:

圖17

2.2 矢量文件的寫出

  在geopandas中使用to_file()來將GeoDataFrameGeoSeries寫出為矢量文件,主要支持shapefileGeoJSON以及GeoPackage,不像geopandas.read_file()可以根據傳入的文件名稱信息自動推斷類型,我們在寫出矢量數據時就需要使用driver參數來聲明文件類型:

  • ESRI Shapefile

  我們將上文最后一次讀入的GeoDataFrame寫出為ESRI Shapefile,設置driver參數為ESRI Shapefile,如果你對文件編碼有要求,這里可以使用encoding參數來指定,譬如這里我們指定為utf-8

'''在工程根目錄下創建output文件夾'''
import os

try:
    os.mkdir('output')
except FileExistsError:
    pass
    
data.to_file('output/output.shp', 
             driver='ESRI Shapefile',
             encoding='utf-8')

  可以看到在output文件夾下,成功導出了完整的shapefile

圖18

  而如果導出的文件名不加后綴擴展名,則會生成包含在新目錄下的shapefile

data.to_file('output/output_shapefile', 
             driver='ESRI Shapefile',
             encoding='utf-8')
圖19

  也可以向指定的文件夾下追加圖層:

data.to_file('output/output_shapefile_multi_layer', 
             driver='ESRI Shapefile',
             layer='layer1',
             encoding='utf-8')

data.to_file('output/output_shapefile_multi_layer', 
             driver='ESRI Shapefile',
             layer='layer2',
             encoding='utf-8')

data.to_file('output/output_shapefile_multi_layer', 
             driver='ESRI Shapefile',
             layer='layer3',
             encoding='utf-8')
圖20
  • GeoPackage

  對於gdb文件,由於ESRI的限制,暫時無法在開源的geopandas中導出,但我們可以用QGIS中的GeoPackage作為替代方案(開源世界萬歲O(∩_∩)O~~),只需要將driver參數設置為GPKG即可,這里需要注意一個bug:在使用geopandas導出GeoPackage文件時,可能會出現圖21所示錯誤:

圖21

  但我觀察到即使出現了上述錯誤,GeoPackage文件也是成功保存到路徑下的且整個程序並未被打斷,因此可以無視上述錯誤:

圖22
  • GeoJSON

  寫出為GeoJSON非常容易,只需要設置driver='GeoJSON'即可:

圖23

  以上就是本文的全部內容,如有筆誤望指出!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM