mcpField
G
geopandas-geospatial

geopandas-geospatial

github.com/jaechang-hitsデータ・データベース38476 回インストール6 日前に更新
リポジトリ

geopandas-geospatial について

geopandas-geospatialは、地理ベクターデータを扱うPythonユーザー向けのGeoPandasスキルです。pandas風のデータ操作に加え、空間解析と可視化を扱います。

主な機能

  1. 01複数のベクターファイル形式の読み書き
  2. 02座標参照系の変換
  3. 03空間結合とオーバーレイ分析
  4. 04幾何属性の計算
  5. 05コロプレスマップの作成

活用シーン

  1. 01地域ごとのポイント数の集計
  2. 02施設周辺のバッファー作成
  3. 03複数の地理データソースの統合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill geopandas-geospatial

インストール後、Claude Code で/geopandas-geospatialを入力して読み込まれたか確認します。

詳細

GeoPandas による地理空間分析

概要

GeoPandas は、幾何型に対する空間操作を追加して pandas を拡張し、pandas の DataFrame と Shapely のジオメトリ、ファイル入出力用の Fiona を組み合わせます。使い慣れた pandas に似た API を使用して、地理空間ベクターデータ(点、線、ポリゴン)の読み込み、書き込み、操作、可視化ができます。

使用する場面

  • 空間ファイル形式(Shapefile、GeoJSON、GeoPackage、Parquet)の読み込みと書き込み
  • 地理データセット間の空間結合(ポリゴン内の点、最近傍検索)の実行
  • オーバーレイ操作(交差、和、差分、クリッピング)の実行
  • 幾何学的なプロパティ(面積、距離、バッファー、重心)の計算
  • コロプレスマップやインタラクティブなウェブマップの作成
  • 座標参照系間でのデータの再投影
  • 属性による空間フィーチャーの集約(dissolve)
  • ラスターデータの分析には、代わりに rasterio/xarray を使用してください
  • 大規模な分散地理空間処理には、Dask-GeoPandas または Apache Sedona を検討してください

前提条件

pip install geopandas matplotlib
# Optional:
# pip install folium       — interactive maps
# pip install mapclassify  — classification schemes for choropleth
# pip install contextily   — basemaps
# pip install pyarrow      — faster I/O (2-4x speedup)
# pip install psycopg2 geoalchemy2  — PostGIS support

クイックスタート

import geopandas as gpd

# Read spatial data
gdf = gpd.read_file("data.geojson")
print(f"Shape: {gdf.shape}, CRS: {gdf.crs}")
print(f"Geometry types: {gdf.geometry.geom_type.unique()}")

# Reproject, compute area, save
gdf_proj = gdf.to_crs("EPSG:3857")
gdf_proj['area_m2'] = gdf_proj.geometry.area
gdf_proj.to_file("output.gpkg")

# Quick map
gdf.plot(column='population', legend=True, figsize=(10, 8))

コア API

1. データ入出力
import geopandas as gpd

# Read various formats
gdf = gpd.read_file("data.shp")           # Shapefile
gdf = gpd.read_file("data.geojson")       # GeoJSON
gdf = gpd.read_file("data.gpkg")          # GeoPackage
gdf = gpd.read_file("data.gpkg", layer="roads")  # Specific layer

# Filtered reading (load only needed data)
gdf = gpd.read_file("data.gpkg", bbox=(xmin, ymin, xmax, ymax))
gdf = gpd.read_file("data.gpkg", columns=["name", "geometry"])
gdf = gpd.read_file("data.gpkg", where="population > 10000")

# Arrow acceleration (2-4x faster)
gdf = gpd.read_file("data.gpkg", use_arrow=True)

# Parquet/Feather (columnar, fast, preserves CRS)
gdf = gpd.read_parquet("data.parquet")
gdf.to_parquet("output.parquet")

# PostGIS database
from sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@host/db")
gdf = gpd.read_postgis("SELECT * FROM parcels", con=engine, geom_col='geom')
gdf.to_postgis("output_table", con=engine)

# Write
gdf.to_file("output.gpkg")             # GeoPackage (recommended)
gdf.to_file("output.shp")              # Shapefile
gdf.to_file("output.geojson", driver="GeoJSON")
2. CRS の管理
# Check current CRS
print(gdf.crs)                  # e.g., EPSG:4326
print(gdf.crs.is_geographic)    # True for lat/lon
print(gdf.crs.is_projected)     # True for meters

# Reproject (transforms coordinates)
gdf_proj = gdf.to_crs("EPSG:3857")       # Web Mercator
gdf_proj = gdf.to_crs(epsg=32633)        # UTM zone 33N

# Set CRS (only when metadata missing, does NOT transform coordinates)
gdf = gdf.set_crs("EPSG:4326")

# Estimate appropriate UTM zone
utm_crs = gdf.estimate_utm_crs()
gdf_utm = gdf.to_crs(utm_crs)

一般的な EPSG コード:

CodeNameUse
4326WGS 84GPS 座標、ウェブデータ
3857Web Mercatorウェブマッピング(Google/OSM タイル)
326xxUTM zones (N)面積/距離の計算
5070Albers Equal Area (US)面積を保持する米国の地図
3. 幾何操作
# Buffer (expand/erode geometry by distance)
buffered = gdf.geometry.buffer(100)      # 100 units (meters if projected)
eroded = gdf.geometry.buffer(-50)        # Negative = erosion

# Simplify (reduce complexity)
simplified = gdf.geometry.simplify(tolerance=10, preserve_topology=True)

# Centroid, convex hull, envelope
centroids = gdf.geometry.centroid
hulls = gdf.geometry.convex_hull
bounds = gdf.geometry.envelope

# Union all geometries
unified = gdf.geometry.union_all()

# Affine transformations
rotated = gdf.geometry.rotate(angle=45, origin='center')
scaled = gdf.geometry.scale(xfact=2.0, yfact=2.0)
translated = gdf.geometry.translate(xoff=100, yoff=50)

# Geometric properties
areas = gdf.geometry.area           # Use projected CRS for accuracy
lengths = gdf.geometry.length       # Perimeter for polygons
is_valid = gdf.geometry.is_valid    # Validate geometry
total = gdf.geometry.total_bounds   # [minx, miny, maxx, maxy]
4. 空間分析
# Spatial join (combine datasets by spatial relationship)
joined = gpd.sjoin(points_gdf, polygons_gdf, predicate='intersects')
joined = gpd.sjoin(gdf1, gdf2, predicate='within')
joined = gpd.sjoin(gdf1, gdf2, predicate='contains', how='left')

# Nearest neighbor join
nearest = gpd.sjoin_nearest(gdf1, gdf2, max_distance=1000, distance_col='dist')

# Overlay operations (set-theoretic)
intersection = gpd.overlay(gdf1, gdf2, how='intersection')
union = gpd.overlay(gdf1, gdf2, how='union')
difference = gpd.overlay(gdf1, gdf2, how='difference')
sym_diff = gpd.overlay(gdf1, gdf2, how='symmetric_difference')

# Dissolve (aggregate by attribute)
dissolved = gdf.dissolve(by='region', aggfunc='sum')
dissolved = gdf.dissolve(by='region', aggfunc={'population': 'sum', 'area': 'mean'})

# Clip to boundary
clipped = gpd.clip(gdf, boundary_gdf)

# Distance calculations (use projected CRS)
distances = gdf.geometry.distance(single_point)

# Spatial predicates
within_mask = gdf1.geometry.within(gdf2.geometry)
intersects_mask = gdf1.geometry.intersects(gdf2.geometry)
5. 可視化
import matplotlib.pyplot as plt

# Basic plot
gdf.plot(figsize=(10, 8))

# Choropleth map
gdf.plot(column='population', cmap='YlOrRd', legend=True, figsize=(12, 8))

# Classification schemes (requires mapclassify)
gdf.plot(column='population', scheme='quantiles', k=5, legend=True)
gdf.plot(column='population', scheme='fisher_jenks', k=5, legend=True)

# Multi-layer map
fig, ax = plt.subplots(figsize=(12, 10))
polygons_gdf.plot(ax=ax, color='lightblue', edgecolor='black')
points_gdf.plot(ax=ax, color='red', markersize=10)
roads_gdf.plot(ax=ax, color='gray', linewidth=0.5)
ax.set_title('Multi-layer Map')
ax.set_axis_off()

# Interactive map (requires folium)
m = gdf.explore(column='population', cmap='YlOrRd', legend=True,
                tooltip=['name', 'population'])
m.save('map.html')

# Multi-layer interactive
m = gdf1.explore(color='blue', name='Layer 1')
gdf2.explore(m=m, color='red', name='Layer 2')
import folium
folium.LayerControl().add_to(m)

# Basemap (requires contextily)
import contextily as ctx
gdf_wm = gdf.to_crs(epsg=3857)
ax = gdf_wm.plot(alpha=0.5, figsize=(10, 10))
ctx.add_basemap(ax)

主要な概念

データ構造
  • GeoSeries:空間メソッド(面積、距離、バッファーなど)を備えた、Shapely ジオメトリの Pandas Series です
  • GeoDataFrame:1 つ以上のジオメトリ列を持つ Pandas DataFrame です。列のうち 1 つが、空間メソッドで使用される「アクティブジオメトリ」です
from shapely.geometry import Point

# Create from coordinates
gdf = gpd.GeoDataFrame(
    {'name': ['A', 'B'], 'value': [10, 20]},
    geometry=[Point(0, 0), Point(1, 1)],
    crs="EPSG:4326"
)

# Multiple geometry columns
gdf['centroid'] = gdf.geometry.centroid
gdf = gdf.set_geometry('centroid')  # Switch active geometry
空間操作における CRS のルール
  • 空間操作の前には、必ず CRS を確認してください:print(gdf.crs)
  • 空間結合、オーバーレイ、または距離計算の前に CRS を一致させてください
  • 面積/距離の計算には投影 CRS(メートル)を使用してください。地理 CRS(度)では誤った結果になります
  • set_crs() はメタデータを追加するだけですが、to_crs() は座標を変換します
空間インデックス

GeoPandas は、sjoin、overlay、その他の空間操作用に空間インデックス(R-tree)を自動作成します。手動でクエリを実行する場合:

sindex = gdf.sindex
possible_idx = list(sindex.intersection((xmin, ymin, xmax, ymax)))

一般的なワークフロー

ワークフロー 1:読み込み → 変換 → 分析 → エクスポート
import geopandas as gpd

# Load
gdf = gpd.read_file("parcels.shp")
print(f"CRS: {gdf.crs}, Rows: {len(gdf)}")

# Transform to projected CRS for measurements
gdf = gdf.to_crs(gdf.estimate_utm_crs())

# Analyze
gdf['area_ha'] = gdf.geometry.area / 10000  # hectares
gdf['perimeter_m'] = gdf.geometry.length
print(f"Total area: {gdf['area_ha'].sum():.1f} ha")

# Export
gdf.to_file("parcels_analyzed.gpkg")
ワークフロー 2:空間結合と集約
# Count points per polygon
points_in_poly = gpd.sjoin(points_gdf, polygons_gdf, predicate='within')
counts = points_in_poly.groupby('index_right').agg(
    point_count=('geometry', 'size'),
    total_value=('value', 'sum')
)
result = polygons_gdf.merge(counts, left_index=True, right_index=True, how='left')
result['point_count'] = result['point_count'].fillna(0)
print(f"Polygons with points: {(result['point_count'] > 0).sum()}/{len(result)}")
ワークフロー 3:複数ソースの統合
# Read from different sources, ensure matching CRS
roads = gpd.read_file("roads.shp")
buildings = gpd.read_file("buildings.geojson")
parcels = gpd.read_postgis("SELECT * FROM parcels", con=engine, geom_col='geom')

target_crs = roads.crs
buildings = buildings.to_crs(target_crs)
parcels = parcels.to_crs(target_crs)

# Find buildings within 50m of roads
buildings_near_roads = gpd.sjoin_nearest(
    buildings, roads, max_distance=50, distance_col='road_dist'
)
print(f"Buildings near roads: {len(buildings_near_roads)}/{len(buildings)}")

主要なパラメーター

ParameterFunctionDefaultEffect
predicatesjoin'intersects'空間的な関係:intersects、within、contains、touches、crosses
howsjoin, overlay'inner'結合の種類:inner、left、right
max_distancesjoin_nearestNone検索半径の上限(パフォーマンスが向上します)
ksjoin_nearest1検索する最近傍の数
tolerancesimplifyRequiredDouglas-Peucker 許容値(CRS の単位)
preserve_topologysimplifyTrue自己交差を防止します
resolutionbuffer16バッファー曲線のセグメント数
aggfuncdissolve'first'ジオメトリ以外の列に適用する集約関数
use_arrowread_fileFalseArrow による高速化を有効にします(2~4 倍高速)
schemeplotNone分類方法:quantiles、equal_interval、fisher_jenks
kplot (with scheme)5分類区分の数

ベストプラクティス

  1. 空間演算を行う前に、必ず CRS を確認してください。CRS が一致していないと、誤った結果や空の結果になります。
  2. 面積や距離の計算には、投影 CRS を使用してください。地理座標 CRS(度)は、計測には意味がありません。
  3. 結合前に CRS を一致させてください。gpd.sjoin(gdf1, gdf2) の前に gdf2 = gdf2.to_crs(gdf1.crs) を実行します。
  4. 複雑な演算の前に .is_valid でジオメトリを検証してください。無効なジオメトリは、気づきにくいエラーの原因になります。
  5. Shapefile より GeoPackage を使用してください。10 文字の列名制限がなく、複数のレイヤーに対応し、パフォーマンスも優れています。
  6. 読み込み時にフィルタリングしてください。大きなファイルでは bbox、columns、where を使用して、必要なデータだけを読み込みます。
  7. sjoin_nearest では max_distance を設定してください。距離を制限しない最近傍検索は、大規模なデータセットでは時間がかかります。
  8. ジオメトリを変更するときは .copy() を使用してください。元の GeoDataFrame に意図しない影響が及ぶのを防げます。

よく使うレシピ

レシピ:ポリゴン内のポイントを数える

使用場面:地域(郡、流域)ごとにポイント観測(サンプル地点、観測値)を集計します。

import geopandas as gpd

regions = gpd.read_file("regions.geojson")
points = gpd.read_file("observations.geojson").to_crs(regions.crs)

joined = gpd.sjoin(points, regions, how="inner", predicate="within")
counts = joined.groupby("index_right").size().rename("point_count")
regions_with_counts = regions.join(counts).fillna(0)
regions_with_counts["point_count"] = regions_with_counts["point_count"].astype(int)
print(regions_with_counts[["name", "point_count"]].sort_values("point_count", ascending=False).head())
レシピ:ポイントの周囲にバッファーを作成し、重複を統合する

使用場面:ポイント位置からサービスエリアや集水域を作成します。

import geopandas as gpd

facilities = gpd.read_file("facilities.geojson")
utm_crs = facilities.estimate_utm_crs()   # Project to meters
facilities_m = facilities.to_crs(utm_crs)

# 1 km buffer
buffers = facilities_m.copy()
buffers["geometry"] = facilities_m.geometry.buffer(1000)

# Dissolve overlapping buffers into single polygon
service_area = buffers.dissolve()
service_area_wgs84 = service_area.to_crs("EPSG:4326")
service_area_wgs84.to_file("service_area.geojson", driver="GeoJSON")
print(f"Service area: {service_area_wgs84.geometry.area.sum():.0f} sq degrees")

トラブルシューティング

問題原因解決策
空間結合の結果が空GeoDataFrame 間で CRS が一致していないCRS が一致していることを確認します:gdf2 = gdf2.to_crs(gdf1.crs)
面積や距離の値が誤っている地理座標 CRS(度)を使用している投影 CRS に再投影します:gdf.to_crs(gdf.estimate_utm_crs())
読み込み時に DriverError が発生するドライバーがない、またはファイルが破損しているファイルが存在することを確認し、driver="GeoJSON" を明示的に指定して試します
マージ後にジオメトリ列が失われるgdf.merge(df) ではなく df.merge(gdf) を呼び出している必ず GeoDataFrame に対して merge を呼び出します
オーバーレイ時に TopologicalError が発生する無効なジオメトリgdf.geometry = gdf.geometry.buffer(0) で修正します
sjoin_nearest が遅い大規模なデータセットで距離制限がないmax_distance パラメーターを設定します
Folium の地図が空白になるジオメトリが EPSG:4326 ではないWGS84 に再投影します:gdf.to_crs(epsg=4326).explore()
Shapefile の列名が切り詰められるShapefile の 10 文字制限代わりに GeoPackage を使用します:gdf.to_file("out.gpkg")

参考資料

関連スキル

  • matplotlib-scientific-plotting — 高度な地図スタイル設定と図のエクスポート
  • polars-dataframes — 空間演算の前後に行う高性能な表形式データ分析
  • folium — geopandas.explore() を超える高度なインタラクティブ Web マッピング

コメント