Najít Minimální počet Kruhů s 50-ti kilometrovém Okruhu, který Pokrývá Všechny Body

0

Otázka

Mít seznam lat/lon bodů, jak můžeme najít minimální počet 50 mil kruhy (a jejich lat/lon bodů) taková, že tyto kruhy pokrývají všechny body v seznamu?

Řešení nemusí být optimální, a výpočet poloměry/vzdálenosti lze aproximovat, pro jednoduchost. Nebo použít helper library jako geopy.distance.

Například, tady je seznam CSV lat/lon bodů:

41.81014,-72.550028
41.995833,-72.581525
41.377211,-72.150307
41.710626,-72.763862
41.55254,-72.815454
41.415022,-73.401914
41.0554,-73.54142
41.660572,-72.725673
41.350949,-72.871673
41.280278,-72.987515
41.23354,-73.151677
41.235174,-73.038092
41.58254,-73.034321
41.89121,-72.6521
41.340446,-73.078943
41.81886,-73.0755
41.228735,-73.225326
41.839019,-71.883778
41.585192,-71.99693
41.611472,-72.901357
41.783976,-72.748229
43.634242,-70.347774
44.842191,-68.74156
43.934038,-69.985271
43.474,-70.5141
44.312403,-69.804993
42.552616,-70.937616
41.877743,-71.068577
41.940344,-71.351931
42.399035,-71.071855
42.168221,-72.642232
42.518609,-71.135461
42.160827,-71.498868
42.481583,-71.024154
42.305328,-71.398387
42.29247,-71.7751
41.796058,-71.321145
42.376695,-71.090028
42.364178,-71.156462
41.971125,-70.716858
42.280435,-71.655929
42.359487,-71.607159
42.503468,-70.919421
42.194395,-71.774687
42.357311,-72.547241
42.328872,-71.062845
42.033714,-71.310581
42.39976,-71.000326
42.527193,-71.71374
42.495264,-73.206116
41.63729,-71.003268
42.110519,-70.927683
42.152383,-71.073541
42.02714,-71.1438
42.740784,-71.161323
41.773672,-70.745562
42.788072,-71.115959
42.623622,-71.318304
42.137401,-70.83883
42.348748,-71.504967
41.749066,-71.207427
42.2045,-71.1553
42.22142,-71.021844
42.589718,-71.159895
42.344172,-71.099961
42.364561,-71.102575
42.2882972,-71.1267483
42.350679,-71.114022
42.494932,-71.103401
42.42072,-71.09902
42.388648,-71.118659
42.484104,-71.186185
41.666927,-70.294616
42.275401,-71.029299
42.299241,-71.062748
42.361045,-71.0626
42.764475,-71.215039
43.2189,-71.485199
42.702771,-71.437791
43.045615,-71.461202
42.79899,-71.53679
42.941002,-71.473513
42.928188,-72.301906
43.235048,-70.884519
43.048951,-70.818587
43.633682,-72.322002
44.466154,-73.18226
gis haversine latitude-longitude maps
2021-11-21 17:57:30
1

Nejlepší odpověď

1

Aktualizováno odpověď na základě připomínky:

Máte mnoho možností.

Zde jsou 3 différents způsoby, jak dělat, že:

1. S scipy.CKDTree:

Klady :

  • To bude rychle

Nevýhody :

  • méně přesné, protože vypočtená vzdálenost je euklidovský
  • a poloměr bude stejná jako své vstupy, tak tady ve stupních

Chtěl bych jít s cKDTree a poloměrem dotazu najít všechny body v okruhu, odstranit teze body ze seznamu, a pokračovat s zbývající body. To není optimální, ale může to být dobrý základ.

from scipy.spatial import cKDTree

points = [(41.81014,-72.550028), (41.995833,-72.581525), (41.377211,-72.150307), (41.710626,-72.763862), (41.55254,-72.815454), (41.415022,-73.401914), (41.0554,-73.54142), (41.660572,-72.725673), (41.350949,-72.871673), (41.280278,-72.987515), (41.23354,-73.151677), (41.235174,-73.038092), (41.58254,-73.034321), (41.89121,-72.6521), (41.340446,-73.078943), (41.81886,-73.0755), (41.228735,-73.225326), (41.839019,-71.883778), (41.585192,-71.99693), (41.611472,-72.901357), (41.783976,-72.748229), (43.634242,-70.347774), (44.842191,-68.74156), (43.934038,-69.985271), (43.474,-70.5141), (44.312403,-69.804993), (42.552616,-70.937616), (41.877743,-71.068577), (41.940344,-71.351931), (42.399035,-71.071855), (42.168221,-72.642232), (42.518609,-71.135461), (42.160827,-71.498868), (42.481583,-71.024154), (42.305328,-71.398387), (42.29247,-71.7751), (41.796058,-71.321145), (42.376695,-71.090028), (42.364178,-71.156462), (41.971125,-70.716858), (42.280435,-71.655929), (42.359487,-71.607159), (42.503468,-70.919421), (42.194395,-71.774687), (42.357311,-72.547241), (42.328872,-71.062845), (42.033714,-71.310581), (42.39976,-71.000326), (42.527193,-71.71374), (42.495264,-73.206116), (41.63729,-71.003268), (42.110519,-70.927683), (42.152383,-71.073541), (42.02714,-71.1438), (42.740784,-71.161323), (41.773672,-70.745562), (42.788072,-71.115959), (42.623622,-71.318304), (42.137401,-70.83883), (42.348748,-71.504967), (41.749066,-71.207427), (42.2045,-71.1553), (42.22142,-71.021844), (42.589718,-71.159895), (42.344172,-71.099961), (42.364561,-71.102575), (42.2882972,-71.1267483), (42.350679,-71.114022), (42.494932,-71.103401), (42.42072,-71.09902), (42.388648,-71.118659), (42.484104,-71.186185), (41.666927,-70.294616), (42.275401,-71.029299), (42.299241,-71.062748), (42.361045,-71.0626), (42.764475,-71.215039), (43.2189,-71.485199), (42.702771,-71.437791), (43.045615,-71.461202), (42.79899,-71.53679), (42.941002,-71.473513), (42.928188,-72.301906), (43.235048,-70.884519), (43.048951,-70.818587), (43.633682,-72.322002), (44.466154,-73.18226)]

# Radius of circle. Note that the unit is the same as in your list (here, degrees.)
radius = 1

num_circles = 0

list_is_no_empty = True

while(list_is_no_empty):

    # Take the first point in order to find all points within distance radius
    start_point = points[0]

    # Create a KDTree
    tree = cKDTree(points)

    # Find indexes of all points in radius
    indexes_of_points_in_radius = tree.query_ball_point(start_point, radius)

    # Create the list of points to remove (points that were found within distance radius)
    points_to_remove = [points[i] for i in indexes_of_points_in_radius]

    # Remove these points
    points = list(set(points) - set(points_to_remove))

    # Increment the number of circles
    num_circles += 1

    # If no points remain, exit loop
    if points == []:
        list_is_no_empty = False

print("Number of circles:", num_circles)

2. S sklearn.sousedé.BallTree:

Klady:

  • Bude to přesnější, protože vypočtená vzdálenost je zde velký kruh vzdálenost (Haversine vzorce).

Nevýhody:

  • Jako cKDTree, poloměr bude stejná jako své vstupy, tak tady ve stupních.
  • Trochu pomalejší, než scipy.cKDTree (2 krát pomalejší, když jsem testoval)

Všimněte si také, že jsem zjistil, že někteří doporučují převést vaše vstupy v radiánech, protože to je nutné pro Haversine vzorce (https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.DistanceMetric.html). Ale z mého zkušebnictví, s scikit-learn 1.0.1, že to nebylo potřeba. Ale jen v případě, že by dělat:

from math import radians
points = [tuple(map(radians, point)) for point in points]
start_point = (radians(start_point[0]), radians(start_point[1]))
radius = radians(radius)

Kód s BallTree:

from sklearn.neighbors import BallTree
import numpy as np

num_circles = 0

list_is_no_empty = True

while(list_is_no_empty):

    # Take the first point in order to find all points within distance radius
    start_point = np.array([points[0]])

    # Create a BallTree, and chose the Haversine formula (great circle distance)
    tree = BallTree(points, metric="haversine")

    # Find indexes of all points in radius
    indexes_of_points_in_radius = tree.query_radius(start_point, r=radius)[0]

    # Create the list of points to remove (points that were found within distance radius)
    points_to_remove = [points[i] for i in indexes_of_points_in_radius]

    # Remove these points
    points = list(set(points) - set(points_to_remove))

    # Increment the number of circles
    num_circles += 1

    # If no points remain, exit loop
    if points == []:
        list_is_no_empty = False

print("Number of circles:", num_circles)

3. S sklearn.sousedé.BallTree, pomocí vzdálenosti definované uživatelem funkce:

Klady :

  • Budeme mít možnost zde využít velmi přesné vzdálenosti
  • Budeme schopni určit tuto vzdálenost v mílích (nebo metrů)

Nevýhody:

  • Způsob pomalejší, než cKDTree (10 krát, když jsem testoval)
from pyproj import Geod
from sklearn.neighbors import BallTree
import numpy as np

# Create a WGS84 ellipsoid
geod = Geod(ellps='WGS84')

# User-defined function for BallTree
# We use the "inv" method of pyproj in order to get the distance in meters between 2 points
# It computes the geodesic distance using the wonderful Karney's algorithm
def geodedsic_distance(point_01, point_02):
    lat1,lon1 = point_01
    lat2,lon2 = point_02
    az12,az21,distance_in_meters = geod.inv(lon1,lat1,lon2,lat2)
    return distance_in_meters

def miles_to_meters(miles):
    return miles * 1609.344

# Radius in miles
radius_in_miles = 50

radius_in_meters = miles_to_meters(50)

num_circles = 0

list_is_no_empty = True

while(list_is_no_empty):

    # Take the first point in order to find all points within distance radius
    start_point = np.array([points[0]])

    # Create a BallTree, and chose our custom function
    tree = BallTree(points, metric=geodedsic_distance)

    # Find indexes of all points in radius, specified in meters
    indexes_of_points_in_radius = tree.query_radius(start_point, r=radius_in_meters)[0]

    # Create the list of points to remove (points that were found within distance radius)
    points_to_remove = [points[i] for i in indexes_of_points_in_radius]

    # Remove these points
    points = list(set(points) - set(points_to_remove))

    # Increment the number of circles
    num_circles += 1

    # If no points remain, exit loop
    if points == []:
        list_is_no_empty = False

print("Number of circles:", num_circles)

Pokud se chcete dozvědět více o km na stupně konverze (a proč, ve skutečnosti, nemůžeme) a výpočetní vzdálenosti na zemi:

Je Haversine Vzorce nebo Vincenty je lepší Vzorec pro výpočet vzdálenosti?

https://gis.stackexchange.com/questions/84885/difference-between-vincenty-and-great-circle-distance-calculations

2021-11-22 00:09:46

Vypadá dobře! Jak konvertovat poloměr kruhu od 50 mil, aby mohl být přiřazen k radius variabilní? Mám použít BallTree s metric='haversine' protože máme co do činění s zeměpisné šířky/délky souřadnice?
Athena Wisdom

Že to není tak jednoduché, jak to vypadá. To je o (alespoň) geodézie a velký kruh vzdálenost. To je úplně nová otázka, a to by bylo nemožné na to odpovědět v komentáři. Budu rád, odpovědět na to, jestli jste po ní (například "Jak převést kilometrů ve stupních v Pythonu?")
Rivers

Myslím, že BallTree je součástí Scikit-Learn, ne SciPy, ale ano, v tomto případě harvesine by být metrický, aby si vybral místo euklidovský.
Rivers

Za rychlost bych reproject na místní souřadný systém pro práci v euklidovský prostor
Ian Turton

Mám to práce s lat/lon převodem bodů na radiány pomocí numpy.deg2rad a pomocí Balltree(points, metric="haversine") Díky!!!
Athena Wisdom

Získat (sbližování) okruh použití s haversine; distance_in_meters = 5000 earth_radius = 6371000 poloměr = distance_in_meters / earth_radius Z: stackoverflow.com/questions/66470898/...
Willem Hendriks

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................