如何有效地计算两个 geopandas 几何图形之间的距离

问题描述 投票:0回答:1

我有两个 geopandas 数据框,一个是点几何,一个是线几何,正在计算几何之间的距离。对于每个点,我计算到相关线几何的距离,其线几何 id 存储在点数据框的一列中以供参考。 计算距离的点特征有 321.113 个。

我正在尝试使用列表理解,但它仍然需要大量时间。太长了,因为我需要对具有更多点特征的更大数据集执行此操作。到目前为止,我的代码如下,

def get_distance(point_lineID, point_FID, point_GEOM, lines_df, points_df):

    ref_line = lines_df.loc[lines_df["line_id"] == point_lineID]

    try:
        d = point_GEOM.distance(ref_line["geometry"]).values[0]
        
    except IndexError:
        d = -99
        

    # Add value to frame
    row_num = points_df[points_df["point_id"] == point_FID].index
    points_df.loc[row_num, "distance_mp"] = d


result = [
    get_distance(point_lineid, point_fid, point_geom, df_lines, df_points)
    for point_lineid, point_fid, point_geom in zip(
        points["line_id"], points["point_id"], points["geometry"]
    )
]

我怎样才能让它更高效? 在这里得到一些解释的支持会很棒。

pandas performance geopandas
1个回答
0
投票

有几种方法可以提高代码的性能。这里有一些建议:

使用矢量化:您可以使用矢量化操作来一次计算所有距离,而不是遍历点 DataFrame 中的每一行。例如,您可以使用带有 lambda 函数的 apply 方法一次将距离计算应用于所有行:

    def get_distance(row, lines_df):
    ref_line = lines_df.loc[lines_df["line_id"] == row["line_id"]]
    try:
        return row["geometry"].distance(ref_line["geometry"]).values[0]
    except IndexError:
        return -99

points["distance_mp"] = points.apply(lambda row: get_distance(row, df_lines), axis=1)

使用空间索引:如果 lines_df DataFrame 非常大,使用空间索引(例如 R-tree)可以显着加快距离计算。您可以使用 geopandas.sindex 模块为 lines_df DataFrame 创建空间索引:

from geopandas.sindex import RTree

# Create spatial index
index = RTree(lines_df.geometry)

def get_distance(row, index, lines_df):
    # Find nearest line using spatial index
    nearest_line_idx = list(index.nearest(row["geometry"].bounds))[0]
    nearest_line = lines_df.loc[nearest_line_idx]

    try:
        return row["geometry"].distance(nearest_line["geometry"])
    except IndexError:
        return -99

points["distance_mp"] = points.apply(lambda row: get_distance(row, index, df_lines), axis=1)

使用Cython或Numba:如果距离计算是你代码中的瓶颈,可以考虑使用Cython或Numba来加速计算。这些工具可以分别将您的 Python 代码编译为更快的 C 代码或机器代码。这是一个使用 Numba 的例子:

import numba as nb

@nb.jit(nopython=True)
def get_distance(point_lineID, point_GEOM, lines_df, line_lengths):
    min_dist = np.inf
    for i in range(len(lines_df)):
        if lines_df[i]["line_id"] == point_lineID:
            dist = point_GEOM.distance(lines_df[i]["geometry"])
            if dist < min_dist:
                min_dist = dist
                line_length = line_lengths[i]
    return min_dist, line_length

# Precompute line lengths for faster access
df_lines["length"] = df_lines["geometry"].length

# Create array of line lengths
line_lengths = df_lines["length"].values

distances = np.zeros(len(points))
for i in nb.prange(len(points)):
    distances[i], line_length = get_distance(points["line_id"][i], points["geometry"][i], df_lines, line_lengths)
    if distances[i] == -1:
        distances[i] = -99
points["distance_mp"] = distances
© www.soinside.com 2019 - 2024. All rights reserved.