2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pandas.DataFrame.apply() で shapely.geometry をつくる

Last updated at Posted at 2021-11-13

対象読者
Pandas, GeoPandas ユーザ
GIS ユーザ

実行環境
Windows 10
Python 3.9.5
geopandas 0.9.0
pandas 1.3.1

はじめに

GeoPandas でジオメトリックな処理をして、shapely.geometry のオブジェクト(Point とか Polygon とか)を geometry カラムに格納する場合を考えます。

xy座標からポイントを作る1とか、既存のオブジェクトのバッファをとる2といった基本的な処理であれば、geopandas の関数や geopandas.GeoSeries のメソッドで楽に実現できます。

ただ実際は、特殊な処理をして複雑なオブジェクトを作りたい場合があります。

ここでは、pandas.DataFrame.apply() を使って、複雑な形状のオブジェクトを作りたいと思います。

pandas.DataFrame.apply()

pandas を使っているとお世話になることの多い apply() ですが、ここでおさらいをします。

公式リファレンス
pandas.DataFrame.apply

データフレームの列や行に対して関数を適用するメソッドですが、ここではgeopandas.GeoDataFrame の geometry カラムを作りたいので、列の処理を考えます。

DataFrame で列に対する処理をする場合は引数 axis=1 を指定します。

今回の趣旨に沿って apply メソッドの使用例を示します。
(使用法を網羅するものではありません)

処理する pandas.DataFrame はこちら。

import pandas as pd

df = pd.DataFrame([[1, 2], [3, 4], [5, 6]], columns=['A', 'B'])

print(df)
'''
   A  B
0  1  2
1  3  4
2  5  6
'''

python組み込み関数を列に適用

C列に、A列の値を2進数にして格納

df['C'] = df['A'].apply(bin)

自作関数を列に適用

D列に、A列とB列の和を格納

def add_ab(row):
    return row['A'] + row['B']

df['D'] = df.apply(add_ab, axis=1)

無名関数を列に適用

E列に、A列とB列の差を格納

df['E'] = df.apply(lambda row: row['A'] - row['B'], axis=1)

なお lambda 式の中で row.name とするとインデックスにでアクセスできます。

複数の引数をとる関数を列に適用

F列に、A列のm(=2)倍とB列のn(=3)倍の和を格納

def add_am_bn(row, m, n):
    return row['A'] * m + row['B'] * n

df['F'] = df.apply(add_am_bn, axis=1, m=2, n=3)

apply の引数として、キーワード引数を渡します。

複数の返り値を複数の列に返す

G列に、A列の2乗を、H列にB列の3乗を返す

def square_a_cube_b(row):
    return row['A']**2, row['B']**3

df[['G', 'H']] = df.apply(square_a_cube_b, axis=1, result_type='expand')

apply の result_type 引数に'expand'を指定します。

結果

print(df)
'''
   A  B      C   D  E   F   G    H
0  1  2    0b1   3 -1   8   1    8
1  3  4   0b11   7 -1  18   9   64
2  5  6  0b101  11 -1  28  25  216
'''
# C列: A列の値を2進数にして格納
# D列: A列とB列の和を格納
# E列: A列とB列の差を格納
# F列: A列のm(=2)倍とB列のn(=3)倍の和を格納
# G列: A列の2乗
# H列: B列の3乗

十字マーク入りのひし形を散りばめる

本題に入ります。

GeoPandas の GeoDataFrame に geometry カラムを設定する例です。

点(x, y)の座標をもとに、
交点(x+a, y+b)、長さ(x方向 c、y方向 d)の十字マーク(マルチライン)と
中心(x+a, y+b)、対角線(x方向 2c, y方向 2d)のひし形(ポリゴン)
を作ります。

こう書かれてもよく分からないと思いますが、十字マーク入りのひし形になります。

先に結果を載せます。
view_qgis.PNG
出力したシェープファイルをQGISで表示しています。

コード

複数の引数をとり、複数のオブジェクトを返す自作関数 xy2geometries() を引数として、x座標 と y座標 をカラムにもつ GeoDataFrame に apply() します。

import random

import geopandas as gpd
from shapely.geometry import MultiLineString
from shapely.geometry import Polygon

fp_cross = 'cross.shp'
fp_diamond = 'diamond.shp'

# apply する自作関数
def xy2geometries(row, a, b, c, d):
    x = row['x']
    y = row['y']
    # 十字マーク
    coords_cross = [
        ((x+a-c/2, y+b), (x+a+c/2, y+b)),
        ((x+a, y+b-d/2), (x+a, y+b+d/2))
    ]
    cross = MultiLineString(coords_cross)
    # ひし形
    coords_diamond = [
        (x+a-2*c/2, y+b),
        (x+a, y+b-2*d/2),
        (x+a+2*c/2, y+b),
        (x+a, y+b+2*d/2)
    ]
    diamond = Polygon(coords_diamond)

    return cross, diamond


# ランダムな10点のx座標とy座標
gdf = gpd.GeoDataFrame({
    'x': [random.randint(-100, 100) for _ in range(10)],
    'y': [random.randint(-100, 100) for _ in range(10)]
})

# 2列にそれぞれ十字マーク(ライン)とひし形(ポリゴン)を格納
# ここで apply() を使います
gdf[['cross', 'diamond']] = gdf.apply(
    xy2geometries, axis=1, result_type='expand', a=5, b=6, c=7, d=8
)

# geometryカラムを指定
gdf_cross = gdf.set_geometry('cross')
gdf_diamond = gdf.set_geometry('diamond')

# シェープファイル出力
gdf_cross[['x', 'y', 'cross']].to_file(fp_cross)
gdf_diamond[['x', 'y', 'diamond']].to_file(fp_diamond)

最後に

Pandas の apply() のおさらいと、GeoPandas の GeoDataFrame への応用について書きました。

for文を使うことなく複雑な列処理を高速にできるというのが apply() の魅力だと思います。

今回は十字マークとひし形にしましたが、ほかにも例えば、角度と長さで矢印を書いたりメッシュコードからメッシュを作成したりと応用できそうです。

  1. geopandas.points_from_xy

  2. geopandas.GeoSeries.buffer

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?