我有两个 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"]
)
]
我怎样才能让它更高效? 在这里得到一些解释的支持会很棒。
有几种方法可以提高代码的性能。这里有一些建议:
使用矢量化:您可以使用矢量化操作来一次计算所有距离,而不是遍历点 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