按位置合并叠加数据帧(Pandas/GeoPandas)

Merging overlaying Dataframes by location (Pandas/GeoPandas)

嗨(这是我的第一个post),

我有 2 个 Pandas 数据框。第一个有大约 80k 个大小为 1km x 1km 的多边形,第二个有大约 100k 个大小为 250mx250m 的多边形。它们基本上是包含不同信息的国家/地区的 2 张地图。所有较小的多边形都在一个大多边形内。 我想要做的是将数据从与大多边形对应的数据帧复制到与内部的小多边形对应的数据帧上。

有什么有效的方法吗?

到目前为止,我所尝试的只是一种使用 shapely 中的“contains(.)”函数的蛮力方法。但是 运行 这个嵌套循环大约需要 2 天..

感谢任何有帮助的评论!

        micro_df = pd.read_csv("Micro_250m_mit_Polygon_geometry.csv", sep=",",nrows=5000)

df = pd.read_csv("MergedWithFigures_Merged_ALL.csv", sep=",",nrows=5000)
df["geometry"] = df["geometry"].apply(wkt.loads)

gdf = geo.GeoDataFrame(df,crs="EPSG:4326")

micro_gdf = geo.GeoDataFrame(micro_df, geometry=geo.points_from_xy(micro_df.MP_X, micro_df.MP_Y),crs="EPSG:4326")
#micro_gdf = micro_gdf.to_crs("EPSG:31287")
print(micro_gdf.crs == gdf.crs)


Joined_gdf = geo.sjoin(micro_gdf, gdf)

gdf_big_v = (
    micro_gdf.sjoin(gdf, predicate="contains")
    .groupby(level=0)
    .agg(
        geometry=("geometry", "first"),
        #vals=("value", lambda s: ",".join(s.astype(str))),
        sum=("AverageDOWNLOAD"),
    )
    .pipe(lambda d: gpd.GeoDataFrame(d, geometry=d["geometry"], crs=micro_gdf.crs))
)

这是我收到的当前错误消息:

AttributeError: 'GeoDataFrame' object has no attribute 'sjoin'

这对我来说意义不大,因为 sjoin() 的文档指出它用于合并 2 个 GeoDataframes... 我也试过使用

JOINED = geo.sjoin(micro_gdf,gdf,how="left") 

这确实合并了 GeoDataframes,但是来自 gdf ​​的新条目都设置为 NaN。

这是地图的一小部分 image,blue/green 中的大方块和下方橙色的小方块。

总而言之,如果小多边形在大多边形内,我希望将大多边形数据框中“AverageDOWNLOAD”列中的数据复制到小多边形数据框中。 (这里我使用了小多边形的中心点,但这应该没有什么区别(?))

  • 已生成 9 个多边形,覆盖 81 个较小的多边形
  • 现在 sjoin() 较大的多边形到具有
  • 的较小多边形
  • 有了这个几何图形,一个大的多边形覆盖了 9 个较小的多边形。因此需要使用 pandas 核心功能来汇总结果。已生成两个聚合结果。 1. 逗号分隔值 2. 值总和
  • 还演示了将属性从大多边形转换为小多边形
  • 终于能够理解这提供了一个 folium 可视化
import shapely
import geopandas as gpd
import numpy as np
import folium

world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

a, b, c, d = world.loc[world["name"].eq("Ukraine")].total_bounds.round(6)
g = 0
# generate some polygons that will cover other polygons
gdf_big = None
gdf_small = None
for i, dims in enumerate([(4, 4), (10, 10)]):
    gdf = gpd.GeoDataFrame(
        geometry=[
            shapely.geometry.box(minx + g, miny + g, maxx - g, maxy - g)
            for minx, maxx in zip(
                np.linspace(a, c, dims[0]), np.linspace(a, c, dims[0])[1:]
            )
            for miny, maxy in zip(
                np.linspace(b, d, dims[1]), np.linspace(b, d, dims[1])[1:]
            )
        ],
        crs="epsg:4326",
    )
    if i == 0:
        gdf_big = gdf
    else:
        gdf_small = gdf


# add some values to small and big polygons
gdf_small["value"] = gdf_small.index
gdf_big["big_value"] = gdf_big.centroid.x.astype(int).astype(str) + "_" + gdf_big.centroid.y.astype(int).astype(str)

# put big values against small polys
gdf_small = gdf_small.sjoin(gdf_big, predicate="within").drop(columns="index_right")

# sum values of small polygons covered by large polygons
# convert back to geodataframe
gdf_big_v = (
    gdf_big.sjoin(gdf_small, predicate="covers")
    .groupby(level=0)
    .agg(
        geometry=("geometry", "first"),
        vals=("value", lambda s: ",".join(s.astype(str))),
        sum=("value", "sum"),
    )
    .pipe(lambda d: gpd.GeoDataFrame(d, geometry=d["geometry"], crs=gdf_big.crs))
)

# visualise...
m = gdf_small.explore(name="small", color="yellow", height=300, width=500)
m = gdf_big_v.explore(m=m, name="big", color="blue")
folium.LayerControl().add_to(m)
m