Python 如何快速从geodataframe中删除相同的几何图形?

Python 如何快速从geodataframe中删除相同的几何图形?,python,numpy,geopandas,Python,Numpy,Geopandas,在使用itertools.combinations()进行for循环期间,我对项目执行geodataframe修改。我检查是否没有重复的几何图形,在我的例子中是LineString。如果是,我将删除其中一个 pandasdrop_duplicates()方法在这里不起作用,因为我们处理的是具有点坐标的空间几何体,这些点坐标可能分布不同,但由相同的线串表示 import geopandas import itertools gdf = geopandas.read_file('example.g

在使用itertools.combinations()进行for循环期间,我对项目执行geodataframe修改。我检查是否没有重复的几何图形,在我的例子中是LineString。如果是,我将删除其中一个

pandasdrop_duplicates()方法在这里不起作用,因为我们处理的是具有点坐标的空间几何体,这些点坐标可能分布不同,但由相同的线串表示

import geopandas
import itertools

gdf = geopandas.read_file('example.geojson')
for a, b in itertools.combinations(gdf.geometry, 2):
    if a.equals(b) == True:
        try:
            gdf.drop(gdf[gdf['geometry'] == b].index.values, inplace=True)
        except:
            continue

gdf.to_file('example.geojson', driver='GeoJSON')
这段代码运行得很好,但我的文件可能非常大。对于大型文件,执行时间非常长。有没有更快的方法

我在考虑使用numpy将所有几何图形存储在一个矩阵中。但是我不知道如何在矩阵上使用带有numpy的equals()方法(from)。谢谢你的帮助

来自
示例.geojson
的geodataframe如下所示:

                                               geometry  
0       LINESTRING (42.70275 9.94481, 42.70030 9.94783)  
1       LINESTRING (42.70030 9.94783, 42.70275 9.94481)  
2       LINESTRING (42.70275 9.94481, 42.69700 9.97133)  
3       LINESTRING (42.69700 9.97133, 42.70275 9.94481)  
4      LINESTRING (42.60179 10.34216, 42.70030 9.94783) 
...
解决方案。 这是一个受@DanielKonstantinov solution和重复数据消除
启发的完整解决方案。我们将一个geodataframe作为输入,并返回修改后的geodataframe


你能上传一个小的
示例.geojson
文件来使用吗?gdf.geometry是否可以散列?你会用努尼克吗?通过检查每个组合来消除重复将是非常低效的,因为计算机科学,加上你正在修改你正在迭代的容器。@KennyOstrom谢谢。但是没有
nunique
不起作用,因为我想它们是几何体。例如,表中的前两个LineString对于pandas是不同的,但从地理空间的角度来看是相同的,因为它们具有相同的两个坐标。您需要一个可哈希类型,以便可以使用集合。我从“pip install geopandas”中得到了一个错误,所以我只想指出一个集合提供了O(n)重复检测,而组合提供了O(n^2)。另外,当您在容器上进行迭代时,不要修改它——将其作为生成新集合或其他内容的生成器。非常感谢!它工作得很好,而且速度更快。我学到了很多。在
deduplicate deletate
中,我猜
x
中的take_沿_轴是
数据
。我在帖子中上传了这个问题的全局解决方案。@Tim我很高兴能帮上忙!修正了一个打字错误。当你有时间的时候,你能编辑一下标题吗?我想主要的问题不是加速iTertools的组合。在我看来,你在评论中提到的要重要得多。对我来说,理解如何使用像您这样的结构是一个挑战,尤其是如何对它们进行排序。谢谢你的提问)是的,你是对的!我改变了标题,即使不是那样,我想还是更好。总的来说,我现在可以用numpy处理我的表,并避免使用pandas方法,numpy真的令人印象深刻。
import geopandas
import numpy as np
from shapely.geometry import LineString

def solution(frame: geodataframe) -> geodataframe:
    linestring = frame.geometry
    coordinates = [list(x.coords) for x in linestring]

    matrix = np.array(coordinates)
    result = deduplicate(matrix)
    final_result = [list(map(tuple, pair)) for pair in result.tolist()]
    lines = [{'geometry': LineString(pair)} for pair in final_result]
    output = geopandas.GeoDataFrame(lines)

    return output
import numpy as np


def deduplicate(geo_data: np.ndarray # shape == (N, 4)
        ) -> np.ndarray:             # deduplicated data with origin order
    data = geo_data.reshape(-1, 2, 2)
    dt = f'f{data.itemsize}' # f4 or f8
    data = data.view([('x', dt), ('y', dt)]) 
    # eliminate differences
    ixs = np.argsort(data, -2, order=('x', 'y'))
    data_no_df = np.take_along_axis(data, ixs, axis=-2) # sorted by 'x' then by 'y'
    # get unique
    unique_sorted_data, uni_ixs = np.unique(data_no_df, True, axis=0)
    uni_ixs.sort() # inplace sort 1d-array
    data_deduplicated = geo_data[uni_ixs] # unique, originally ordered and shaped
    return data_deduplicated


def _test():
    geo_data = np.array([[42.70275,  9.94481, 42.7003 ,  9.94783],
                         [42.7003 ,  9.94783, 42.70275,  9.94481],
                         [42.70275,  9.94481, 42.697  ,  9.97133],
                         [42.697  ,  9.97133, 42.70275,  9.94481],
                         [42.60179, 10.34216, 42.7003 ,  9.94783]])
    data_deduplicated = deduplicate(geo_data)
    print(data_deduplicated)

>>> _test()
[[42.70275  9.94481 42.7003   9.94783]
 [42.70275  9.94481 42.697    9.97133]
 [42.60179 10.34216 42.7003   9.94783]]

large_data = np.random.randint(0, 10, size=(1000, 4)).astype('d')

%timeit deduplicate(large_data)
1.98 ms ± 9.37 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)