web-dev-qa-db-ja.com

Geopandasを使用して最も近いフィーチャまでの距離を計算します

私はArcPyと同等のことをしたいと思っています Generate Near Table Geopandas/Shapelyを使用しています。私はGeopandasとShapelyに非常に慣れておらず、機能する方法論を開発しましたが、それを行うためのより効率的な方法があるかどうか疑問に思っています。

国勢調査細分区の重心とレストランの2つのポイントファイルデータセットがあります。国勢調査細分区の重心ごとに、最も近いレストランまでの距離を探しています。同じレストランが複数のブロックに最も近いレストランであるという点で制限はありません。

これが私にとってもう少し複雑になる理由は、 Geopandas距離関数 が要素ごとに計算し、インデックスに基づいてマッチングするためです。したがって、私の一般的な方法は、Restaurantsファイルをマルチポイントファイルに変換してから、blocksファイルのインデックスをすべて同じ値に設定することです。次に、すべてのブロック重心とレストランのインデックス値は同じになります。

import pandas as pd
import geopandas as gpd
from shapely.geometry import Polygon, Point, MultiPoint

BlockCentroidとRestaurantShapefilesを読んでください。

Blocks=gpd.read_file(BlockShp)
Restaurants=gpd.read_file(RestaurantShp)

Geopandas距離関数は距離を要素ごとに計算するため、RestaurantGeoSeriesをMultiPointGeoSeriesに変換します。

RestMulti=gpd.GeoSeries(Restaurants.unary_union)
RestMulti.crs=Restaurants.crs
RestMulti.reset_index(drop=True)

次に、要素ごとの計算の回避策として、ブロックのインデックスを0(レストランのマルチポイントと同じ値)に設定します。

Blocks.index=[0]*len(Blocks)

最後に、Geopandas距離関数を使用して、各ブロック重心の最寄りのレストランまでの距離を計算します。

Blocks['Distance']=Blocks.distance(RestMulti)

これのあらゆる側面をどのように改善できるかについての提案を提供してください。私はGeopandasやShapelyの使用に縛られていませんが、ArcPyの代替手段を学びたいと思っています。

助けてくれてありがとう!

11
AJG519

私があなたの問題を正しく理解していれば、ブロックとレストランは非常に異なる次元を持つ可能性があります。このため、インデックスを再作成してテーブル形式に強制しようとするのはおそらく悪いアプローチです。

ブロックをループして、レストランまでの最小距離を取得します(@shongololoが提案したように)。

私はもう少し一般的になり(すでにこのコードを書き留めているので)、ポイントからラインまでの距離を取りますが、同じコードがポイントからポイントへ、またはポリゴンからポリゴンへと機能するはずです。ポイントのGeoDataFrameから始めて、線までの距離が最小の新しい列を作成します。

_%matplotlib inline
import matplotlib.pyplot as plt
import shapely.geometry as geom
import numpy as np
import pandas as pd
import geopandas as gpd

lines = gpd.GeoSeries(
    [geom.LineString(((1.4, 3), (0, 0))),
        geom.LineString(((1.1, 2.), (0.1, 0.4))),
        geom.LineString(((-0.1, 3.), (1, 2.)))])

# 10 points
n  = 10
points = gpd.GeoSeries([geom.Point(x, y) for x, y in np.random.uniform(0, 3, (n, 2))])

# Put the points in a dataframe, with some other random column
df_points = gpd.GeoDataFrame(np.array([points, np.random.randn(n)]).T)
df_points.columns = ['Geometry', 'Property1']

points.plot()
lines.plot()
_

enter image description here

次に、ポイントからラインまでの距離を取得し、各ポイントの最小距離のみを保存します(適用されたバージョンについては以下を参照してください)

_min_dist = np.empty(n)
for i, point in enumerate(points):
    min_dist[i] = np.min([point.distance(line) for line in lines])
df_points['min_dist_to_lines'] = min_dist
df_points.head(3)
_

これは

_    Geometry                                       Property1    min_dist_to_lines
0   POINT (0.2479424516236574 2.944916965334865)    2.621823    0.193293
1   POINT (1.465768457667432 2.605673714922998)     0.6074484   0.226353
2   POINT (2.831645235202689 1.125073838462032)     0.657191    1.940127
_

----編集----

(githubの問題から引用)applyの使用は、pandasでの使用方法とより適切で一貫性があります:

_def min_distance(point, lines):
    return lines.distance(point).min()

df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, df_lines)
_

編集:少なくとも2019-10-04の時点で、pandasの変更には、.apply()argsパラメーターを使用して、最後のコードブロックで別の入力が必要になるようです。 :

_df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, args=(df_lines,))
_
15
cd98

コードに詳細がありません、args = (df_lines)

def min_distance(point, lines):
    return lines.distance(point).min()

df_points['min_dist_to_lines'] = df_points.geometry.apply(min_distance, args=(df_lines,))# Notice the change to this line
0
Marcos Tenório