代码之家  ›  专栏  ›  技术社区  ›  Red Sparrow

如何放置X和Y坐标位于多边形外部的数据帧行

  •  2
  • Red Sparrow  · 技术社区  · 7 年前

    我试图解决以下问题。让我们假设一个数据帧(从txt文件加载)具有以下结构(和数千行):

    foo.head()
    
             X            Y       Z 
     0  125417.5112  536361.8752 -1750.0
     1  127517.7647  533925.8644 -1750.0
     2  128144.1000  533199.4000 -1750.0
     3  128578.8385  532904.9288 -1750.0
     4  125417.5112  536361.8752 -1750.0
     ....
    

    数据表示X、Y和Z坐标。

    我还有一组定义闭合多边形的点。它们位于numpy阵列中:

    polypoints
    
    array([[ 125417.5112,  536361.8752],
           [ 127517.7647,  533925.8644],
           [ 128144.1   ,  533199.4   ],
           ....
           [ 125417.5112,  536361.8752]])
    

    如何过滤数据框以删除不属于闭合多边形的行?

    我尝试使用 shapely.geometry polygon . 通过执行以下操作:

    poly = Polygon(polypoints)
    

    这很好用。但我不知道如何继续这样做。

    非常感谢您的帮助

    ----编辑---- 请参阅下面的更新解决方案

    3 回复  |  直到 6 年前
        1
  •  3
  •   Red Sparrow    7 年前

    @MrT建议的原始解决方案非常有效。然而,根据拉格·卡西斯(Rutger Kassies)的建议,我也找到了另一个解决方案。首先需要安装geopandas包。然后,以下代码对我有效:

    import geopandas as gpd
    from shapely.geometry import Point, Polygon, MultiPolygon
    # load the data that should be cropped by the polygon
    # this assumes that the csv file already includes 
    # a geometry column with point data as performed below
    dat_gpd = gpd.GeoDataFrame.from_csv(r'{}\data_to_crop.csv'.format(savedir), sep='\t')
    
    # load the data of the polygon as a dataframe
    arr_df = pd.DataFrame(data, columns=['X','Y','Z'])
    
    # make shapely points out of the X and Y coordinates
    point_data = [Point(xy) for xy in zip(arr_df.X, arr_df.Y)]
    
    # assign shapely points as geometry to a geodataframe
    # Like this you can also inspect the individual points if needed
    arr_gpd = gpd.GeoDataFrame(arr_df, geometry=point_data)
    
    # define a shapely polygon from X and Y coordinates of the shapely points
    polygo = Polygon([[p.x, p.y] for p in arr_gpd.geometry])
    
    # assing defined polygon to a new dataframe
    pol_gpd= gpd.GeoDataFrame()
    pol_gpd['geometry'] = None
    pol_gpd.loc[0,'geometry'] = polygo
    
    # define a new dataframe from the spatial join of the dataframe with the data to be cropped
    # and the dataframe with the polygon data, using the within function.
    dat_fin = gpd.sjoin(dat_gpd, pol_gpd, op = 'within')
    

    如果有人面临类似问题,希望这能有所帮助。此外,还可以找到有关空间连接的更多信息 on the geopandas website . 请注意,此功能不需要在多边形之间进行操作,但也适用于点和多边形

    --编辑--

    %timeit gpd.sjoin(dat_gpd, pol_gpd, op = 'within')
    31.8 s ± 108 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    %timeit dat_gpd['inpoly'] = dat_gpd.apply(lambda row: polygo.intersects(Point(row["X"], row["Y"])), axis = 1)
    1min 26s ± 389 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    看来geo熊猫的功能要快得多。虽然为了公平起见,非地理熊猫解决方案还必须将X和Y转换为形状点元素,然后执行交点评估

        2
  •  2
  •   Mr. T Andres Pinzon    6 年前

    我不太熟悉 shapely . 也许他们有真正的熊猫支持。好吧,它们支持矢量化的numpy函数,所以我不会感到惊讶。
    找出给定多边形内的点的一种方法是使用熊猫 apply() 功能:

    import pandas as pd
    from shapely.geometry import Polygon, Point
    #your dataframe of points
    df = pd.DataFrame([[0, 0, 0], [1, 2, 3], [2, 2, 2], [3, 2, 1] ], columns = list("XYZ"))
    #your polygon points
    polygon1_list = [(1, 1), (1, 3), (3, 3), (3, 1)]
    #adding a column that contains a boolean variable for each point
    df["polygon1"] = df.apply(lambda row: Polygon(polygon1_list).contains(Point(row["X"], row["Y"])), axis = 1)
    print(df)
    

    我的玩具数据集的输出

       X  Y  Z  polygon1
    0  0  0  0   False
    1  1  2  3   False
    2  2  2  2    True
    3  3  2  1   False
    

    身材匀称, contains 实际上意味着在多边形内,这将排除边界。如果要包括边框,应使用 intersects

    df["polygon1"] = df.apply(lambda row: Polygon(polygon1_list).intersects(Point(row["X"], row["Y"])), axis = 1)
    

    现在你的问题的答案很简单。只需删除包含 False 在此新列中:

    df = df.drop(df[~df["polygon1"]].index)
    

    不幸的是,您仍然必须在多边形列表上循环。如果有人知道如何在没有(显式)循环的情况下测试所有点和所有多边形,那将很有趣。我见过一个MultiPolygon构造函数类 on their website ,因此,也许将所有多边形组合在一个类中就可以了。但事先测试这是一个有效的选择。如果多边形的成员沿直线接触无限多个点,则多边形无效。

    编辑:在Python 2.7中,这似乎不起作用。 See akozi's answer for a 2.7 compatible answer.

        3
  •  1
  •   akozi    6 年前

    我在模仿 exact solution Mr T 中建议的 Python 2.7 . 这是我要做的一点小小的改变 Python 2.7 .

    from shaply.geometry.polygon import Polygon
    inside = Polygon(poly_points).contains_points(zip(df.X.values, df.Y.values))
    df['inside'] = inside
    df = df.drop(df[~df['inside']].index)
    

    旧版本的contains\u points似乎无法使用单个点运行。所以我将其设置为读取所有点,并将该列表附加为新列。