H3网格单元在时区多边形中重复出现

编程语言 2026-07-10

我正在尝试生成一个数据集,将H3分辨率为6 的网格单元映射到时区,以便通过H3到 H3的连接更快速地为一个地理空间/时间数据集生成本地日期时间条目,而不是进行地理空间连接(例如,contains)。我使用Apache Spark和 Sedona来完成这项工作,并使用来自 这里 的timezones-with-oceans-now.geojson.zip数据集。到目前为止,我发现有超过40,000个 H3分辨率为6 的单元格在两个时区中重复(没有一个在三个时区中重复)。以下是我的代码:

import pyspark.sql.functions as sql_functions
from sedona.spark.sql import st_functions as stf

timezones = (
    sedona.read.format("geojson")
    .load("s3a://my_bucket/timezones/*.json")
    .option("multiline", "true")
    .selectExpr("explode(features) as features")
    .select("features.*")
    .withColumn("timezone_id", sql_functions.expr("properties['tzid']"))
    .drop("properties", "type")
    .repartition(200)
    .select(
        "timezone_id",
        sql_functions.explode(stf.ST_H3CellIDs("geometry", 6, False)).alias("h3_res6")
    )
)

重复项在以下查询中显示:

(
    timezones
    .groupBy("h3_res6")
    .agg(
        sql_functions.collect_set("timezone_id").alias("timezone_ids"), 
        sql_functions.count("*").alias("count")
    )
    .filter(sql_functions.col("count") > 1)
    .groupBy("timezone_ids")
    .agg(
        sql_functions.array_size(
            sql_functions.collect_set("h3_res6")
        ).alias("num_h3_res6")
    )
    .orderBy(sql_functions.col("num_h3_res6").desc())
    .show(25, truncate=False)
)

+----------------------------------------+-----------+
|timezone_ids                            |num_h3_res6|
+----------------------------------------+-----------+
|[Asia/Manila, Asia/Dhaka]               |40001      |
|[Europe/Moscow, Asia/Dubai]             |352        |
|[Asia/Gaza, Asia/Jerusalem]             |116        |
|[America/Los_Angeles, America/Anchorage]|67         |
|[America/New_York, America/Halifax]     |14         |
|[Asia/Kolkata, Asia/Kathmandu]          |14         |
|[Asia/Dhaka, Asia/Karachi]              |9          |
|[Asia/Manila, Asia/Tokyo]               |8          |
|[Africa/Lagos, Europe/Paris]            |5          |
|[America/Anchorage, America/Phoenix]    |4          |
|[Asia/Jakarta, Asia/Yangon]             |4          |
|[Europe/Moscow, Asia/Karachi]           |3          |
|[Asia/Kolkata, Asia/Dhaka]              |2          |
|[Africa/Casablanca, Europe/Paris]       |2          |
|[Africa/Johannesburg, Europe/Moscow]    |2          |
|[Asia/Jakarta, Asia/Manila]             |1          |
|[Asia/Tokyo, Australia/Brisbane]        |1          |
|[America/Los_Angeles, Pacific/Gambier]  |1          |
|[Europe/Athens, Africa/Johannesburg]    |1          |
|[America/Denver, America/Phoenix]       |1          |
|[Pacific/Honolulu, Pacific/Pago_Pago]   |1          |
+----------------------------------------+-----------+

我以为使用 fullCover=False 意味着使用H3单元格质心来确定该单元格被分配到哪个多边形。如果确实如此(如有误请纠正我),那么有超过40,000个分辨率为6 的H3单元格的质心恰好位于两个时区之间的边界线上。我猜测另一种可能性是某些时区有重叠的多边形,这会很奇怪。

我的问题是:是否有其他人也遇到过这个问题?这是一个常见/已知的问题吗?如果是,最好的处理方法是什么?我可以通过对每个H3单元格取最小的 timezone_id 来进行确定性去重,但这似乎有些任意。

解决方案

如果你需要一个质心对应一个时区,那么对于这个有歧义的单元格你可能需要创建一个自定义质心。由于这是固定质心,在连接时会对你有帮助。

对于所有这些有歧义的H3单元格,使用时区形状文件和H3单元格多边形来获取交集,作为一个闭合多边形,然后使用Python的 shapely库得到一个自定义的质心。

from shapely.geometry import Polygon 
import h3

# Define two overlapping polygons  
timezone_poly = Timezone shape polygon 
H3_poly = H3 Cell 6 polygon 

# Get the intersection geometry 
intersection_poly = timezone_poly.intersection(H3_poly)

#For each custom polygon create a another lower level of H3 Cell eg: 2 level. Get a list of all cell level2 ids which has only one time zone.

h3_lower_cells = h3.polygon_to_cells(h3.LatLngPoly(intersection_poly), 2)

#Create a pyspark python udf function which based lat/log provide you a centroid either based H3 cell 6 for a custom centroid we calculated.

# mapping lat/long to H3cell6 centroid or custom centroid. reduce the lookup of poly contains to fewer records.
function map_centroid(lat, long, H3cell6, H3cell2):
    ambiguous_cells = set(of h3cell6 ids with multiple timezone)
    map_of_h3cell2_centroid = dictionary of mapping
    cell_timezone_poly = dictionary of [h3cell6, list of timezone and intersection poly]  

    centroid = h3.latlng_to_cell(lat, long, 6)

    if H3cell6 in ambiguous_cells:
        if H3cell2 in map_of_h3cell2_centroid:
            centroid = map_of_h3cell2_centroid[H3cell2]
        else:
            // use the intersection poly of check which timezone poly does it matches. 

            centroid = of the intersection poly.

    return centroid;

这只是一个伪代码,用来给你一个思路,请使用这个PySpark转换。若这个方案对你有帮助,请告诉我是否奏效。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章