Commit 50fbfd14 authored by Joseph Siddons's avatar Joseph Siddons
Browse files

Merge branch 'find_neighbours' into 'main'

feat: Find neighbours

See merge request josidd/geospatialtools!1
parents 22095d34 47e1c8f0
from .neighbours import find_nearest
from .distance_metrics import haversine
__all__ = ["find_nearest", "haversine"]
from numpy import argmin
from bisect import bisect
from typing import TypeVar
from datetime import date, datetime
Numeric = TypeVar("Numeric", int, float, datetime, date)
def _find_nearest(vals: list[Numeric], test: Numeric) -> int:
i = bisect(vals, test) # Position that test would be inserted
# Handle edges
if i == 0 and test <= vals[0]:
return 0
elif i == len(vals) and test >= vals[-1]:
return len(vals) - 1
test_idx = [i - 1, i]
return test_idx[argmin([abs(test - vals[j]) for j in test_idx])]
def find_nearest(vals: list[Numeric], test: list[Numeric]) -> list[int]:
"""
Find the nearest value in a list of values for each test value.
Uses bisection for speediness!
Arguments
=========
vals : list[Numeric]
List of values - this is the pool of values for which we are looking
for a nearest match. This list MUST be sorted. Sortedness is not
checked, nor is the list sorted. An error will be raised if the list
is not sorted.
test : list[Numeric]
List of query values
Returns
=======
A list containing the index of the nearest neighbour in vals for each value
in test.
"""
return [_find_nearest(vals, t) for t in test]
......@@ -14,6 +14,7 @@ packages = ["GeoSpatialTools"]
name = "GeoSpatialTools"
version = "0.1.1"
dependencies = [
"numpy",
]
requires-python = ">=3.11"
authors = [
......
import unittest
from numpy import argmin
from random import choice, sample
from datetime import datetime, timedelta
from GeoSpatialTools import find_nearest
class TestFindNearest(unittest.TestCase):
dates = [
datetime(2009, 1, 1, 0, 0) + timedelta(seconds=i * 3600)
for i in range(365 * 24)
]
test_dates = sample(dates, 150)
test_dates = [
d + timedelta(seconds=60 * choice(range(60))) for d in test_dates
]
test_dates.append(dates[0])
test_dates.append(dates[-1])
test_dates.append(datetime(2004, 11, 15, 17, 28))
test_dates.append(datetime(2013, 4, 22, 1, 41))
def test_nearest(self):
greedy = [
argmin([abs(x - y) for x in self.dates]) for y in self.test_dates
]
ours = find_nearest(self.dates, self.test_dates)
assert ours == greedy
pass
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment