簡體   English   中英

獲取兩個 geopandas 數據框幾何點之間的距離

[英]Getting the distance between two geopandas data frames geometry points

我第一次使用空間數據。 我必須比較兩個具有經緯度和經度詳細信息的數據框。 我已將兩者都轉換為 GeoPandas 數據框。

import pandas as pd
from pandas import DataFrame
import geopandas as gpd
from neighbors import nearest_neighbor


df = pd.DataFrame([[1973,22.525158,88.330775],[1976,72.85136,19.10840],[898,91.78523,26.15012]],columns=['id', 'lat', 'long'])
gdf1 = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.long,df.lat))

df2 = pd.DataFrame([['06c979eaa59f',29.873870,76.965620],['19aedbb2e743',20.087574,76.180045],['5060a3931a43',31.289770,75.572340]],columns=['id','lat','lon']) 
gdf2 = gpd.GeoDataFrame(df2, geometry=gpd.points_from_xy(df2.lon,df2.lat))

我的 DF1 有 100 萬行,而 df2 有大約 7000 行。 我正在嘗試為 DF1 中的每條記錄從 DF2 獲取最近的鄰居。

我試過兩種方法。 兩者都運行得非常快,結果可行。 但是,它們並不准確。

方法一:

請檢查此鏈接

在此頁面中,我使用了sklearn.neighbors中的最近鄰方法。 這將返回以米為單位的結果。 但是,當我從兩個數據幀手動檢查 lat long 之間的距離時,我總是發現最近的鄰居返回 1/4 的距離。

比如上面方法返回的距離是125米,google map和https://www.geodatasource.com/distance-calculator都返回500米左右的距離。 距離的差異一直在返回結果的 4 倍左右波動。

方法二:

在第二種方法中,我遵循了 gis.stackexchange.com 中給出的代碼。

https://gis.stackexchange.com/questions/222315/geopandas-find-nearest-point-in-other-dataframe

import itertools
from operator import itemgetter

import geopandas as gpd
import numpy as np
import pandas as pd

from scipy.spatial import cKDTree
from shapely.geometry import Point, LineString

df = pd.DataFrame([[1973,22.525158,88.330775],[1976,72.85136,19.10840],[898,91.78523,26.15012]],columns=['id', 'lat', 'long'])
gdf1 = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.long,df.lat))

df2 = pd.DataFrame([['06c979eaa59f',29.873870,76.965620],['19aedbb2e743',20.087574,76.180045],['5060a3931a43',31.289770,75.572340]],columns=['id','lat','lon']) 
gdf2 = gpd.GeoDataFrame(df2, geometry=gpd.points_from_xy(df2.lon,df2.lat))

在此,我用自己的數據框替換了 gpd1 和 gpd2。

def ckdnearest(gdfA, gdfB, gdfB_cols=['id']):
    # resetting the index of gdfA and gdfB here.
    gdfA = gdfA.reset_index(drop=True)
    gdfB = gdfB.reset_index(drop=True)
    A = np.concatenate(
        [np.array(geom.coords) for geom in gdfA.geometry.to_list()])
    B = [np.array(geom.coords) for geom in gdfB.geometry.to_list()]
    B_ix = tuple(itertools.chain.from_iterable(
        [itertools.repeat(i, x) for i, x in enumerate(list(map(len, B)))]))
    B = np.concatenate(B)
    ckd_tree = cKDTree(B)
    dist, idx = ckd_tree.query(A, k=1)
    idx = itemgetter(*idx)(B_ix)
    gdf = pd.concat(
        [gdfA, gdfB.loc[idx, gdfB_cols].reset_index(drop=True),
         pd.Series(dist, name='dist')], axis=1)
    return gdf

c = ckdnearest(gdf1, gdf2)

以上運行速度非常快並返回結果。 然而,返回的距離值至少比我得到的低 100 倍。

乘數:107.655914

在此處輸入圖像描述

在上面的 excel pic 中,第一列表示 python 返回的結果,而第二列表示上面給出的同一網站返回的結果。 雖然結果中的這些近似值讓我開始,但我想要准確的結果。 如何比較上面給出的兩個數據框,並為 DF1 中的每一行獲取最准確的最近距離。

處理空間數據時,您應該注意點坐標是從球體投影到平面中的。 在墨卡托投影中,緯度點之間的距離以度為單位,而不是米。 並且轉換取決於點的緯度,因為赤道的 1 度將比高緯度的 1 度少米。

您可以查看此討論以了解此問題的可能解決方案: https://gis.stackexchange.com/questions/293310/how-to-use-geoseries-distance-to-get-the-right-answer

舉個例子,一種可能性是您將地理數據框轉換為覆蓋您所在地區的 UTM 投影。 例如,比利時與 UTM 區域 31N EPSG:32631相交。 墨卡托投影有一個 epsg 代碼 EPSG:4326。 要轉換 GeoDataFrame/GeoSeries,您需要在創建時提供 CRS:

s = gpd.GeoSeries(points, crs=4326)

其中 points 是shapely.geometry.Point的列表

然后轉換為給定的 UTM:

s_utm = s.to_crs(epsg=32631)

現在,您將在s_utm中計算的點之間的距離以米為單位。

但是,您需要確保您的點確實落入給定的 UTM 區域,否則結果將不准確。 我鏈接的答案表明其他方法也可能有效,並且可以應用於整個點的集合。

您也可以嘗試轉換為 EPSG 32663(WGS 84 / 世界等距圓柱),它應該保持距離。

另一種選擇可能是使用geopy ,它允許使用geopy.geodesic.distance計算測地線距離

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM