SED xếp hạng các khoảng cách giống như khoảng cách Euclide, vì vậy có thể chấp nhận sử dụng SED để tìm "hàng xóm gần nhất"
Tôi đại diện cho giải pháp dưới dạng một đối tượng ánh xạ các điểm truy vấn tới điểm tham chiếu gần nhất. e. g
{ [5, 1]: [4, 1] }
Một giải pháp mạnh mẽ cho "Vấn đề hàng xóm gần nhất", đối với mỗi điểm truy vấn, sẽ đo khoảng cách [sử dụng SED] tới mọi điểm tham chiếu và chọn điểm tham chiếu gần nhất
def nearest_neighbor_bf[*, query_points, reference_points]: """Use a brute force algorithm to solve the "Nearest Neighbor Problem". """ return { query_p: min[ reference_points, key=lambda X: SED[X, query_p], ] for query_p in query_points } reference_points = [ [1, 2], [3, 2], [4, 1], [3, 5] ] query_points = [ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ] nearest_neighbor_bf[ reference_points = reference_points, query_points = query_points, ]
{[3, 4]: [3, 5],
[5, 1]: [4, 1],
[7, 3]: [4, 1],
[8, 9]: [3, 5],
[10, 1]: [4, 1],
[3, 3]: [3, 2]}
Độ phức tạp thời gian của giải pháp này là gì?
- Tìm điểm tham chiếu gần nhất cho một điểm truy vấn nhất định mất O[M] bước
- Thuật toán phải tìm điểm tham chiếu gần nhất cho các điểm truy vấn O[N]
Kết quả là, độ phức tạp thời gian tổng thể của thuật toán brute force là
O[N M]
Làm thế nào tôi có thể giải quyết vấn đề này nhanh hơn?
- Tôi luôn lặp lại các điểm truy vấn O[N], vì vậy tôi không thể giảm hệ số N
- Tuy nhiên, có lẽ tôi có thể tìm thấy điểm tham chiếu gần nhất nhỏ hơn O[M] bước [nhanh hơn so với việc kiểm tra mọi điểm tham chiếu]
A là một cấu trúc dữ liệu được sử dụng để tối ưu hóa các truy vấn không gian. e. g
- Điểm tham chiếu gần nhất cho một điểm truy vấn là gì?
- Điểm tham chiếu nào nằm trong bán kính 1 mét của điểm truy vấn?
Cây k chiều [cây k-d] là một chỉ số không gian sử dụng cây nhị phân để phân chia không gian tọa độ thực. Tại sao tôi nên sử dụng cây kd để giải quyết "Bài toán hàng xóm gần nhất"?
- Đối với M điểm tham chiếu, việc tìm kiếm điểm lân cận gần nhất của điểm truy vấn mất trung bình O[log M] thời gian. Thời gian này nhanh hơn thời gian O[M] của thuật toán brute force
Để biết thêm thông tin về cây k-d, hãy đọc các tài liệu này
Tôi xây dựng một cây kd cân bằng bằng cách sử dụng. Đây là một thuật toán đệ quy chia tập hợp các điểm tham chiếu thành một nửa ở trung vị và xây dựng đệ quy các cây con bên trái và bên phải
Đây là một hàm Python,
[3, 4]
2, thực hiện thuật toán xây dựngimport collections import operator BT = collections.namedtuple["BT", ["value", "left", "right"]] BT.__doc__ = """ A Binary Tree [BT] with a node value, and left- and right-subtrees. """ def kdtree[points]: """Construct a k-d tree from an iterable of points. This algorithm is taken from Wikipedia. For more details, > //en.wikipedia.org/wiki/K-d_tree#Construction """ k = len[points[0]] def build[*, points, depth]: """Build a k-d tree from a set of points at a given depth. """ if len[points] == 0: return None points.sort[key=operator.itemgetter[depth % k]] middle = len[points] // 2 return BT[ value = points[middle], left = build[ points=points[:middle], depth=depth+1, ], right = build[ points=points[middle+1:], depth=depth+1, ], ] return build[points=list[points], depth=0] reference_points = [ [1, 2], [3, 2], [4, 1], [3, 5] ] kdtree[reference_points]
BT[value=[3, 5],
left=BT[value=[3, 2],
left=BT[value=[1, 2], left=None, right=None],
right=None],
right=BT[value=[4, 1], left=None, right=None]]
Độ phức tạp về thời gian của việc xây dựng cây k-d từ M điểm là bao nhiêu?
Timsort của Python chạy trong thời gian O[M log M]
Việc xây dựng xây dựng đệ quy các cây con bên trái và bên phải, bao gồm việc sắp xếp hai danh sách có kích thước bằng một nửa danh sách ban đầu
2 O[½M log ½M] ≤ O[M log M]
Kết quả là, mỗi cấp độ của cây mất O[M log M] thời gian để xây dựng
Bởi vì danh sách các điểm được giảm một nửa ở mỗi cấp độ, nên có các cấp độ O[log M] trong cây k-d
Kết quả là, tổng thời gian phức tạp của việc xây dựng cây k-d là
O[M [log M]2]
Để tìm kiếm hàng xóm gần nhất, tôi sử dụng. Thuật toán này là một biến thể của việc tìm kiếm cây tìm kiếm nhị phân
Đây là một hàm Python,
[3, 4]
3, thực hiện thuật toán tìm kiếm này0[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
1Độ phức tạp thời gian trung bình của tìm kiếm hàng xóm gần nhất trong cây k-d cân bằng của M điểm là
O[log M]
Tôi kết hợp
[3, 4]
2 và [3, 4]
3 để tạo ra một giải pháp mới cho "Vấn đề hàng xóm gần nhất"2[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
{[3, 4]: [3, 5],
[5, 1]: [4, 1],
[7, 3]: [4, 1],
[8, 9]: [3, 5],
[10, 1]: [4, 1],
[3, 3]: [3, 2]}
4[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
5Độ phức tạp thời gian của thuật toán này là gì?
- Xây dựng cây k-d mất O[M [log M]2]] thời gian
- Mỗi lần tìm kiếm hàng xóm gần nhất mất thời gian O[log M]
- O[N] tìm kiếm hàng xóm gần nhất được tiến hành
Kết quả là, độ phức tạp thời gian tổng thể của
[3, 4]
6 làO[M [log M]2 + N log M]
Điều này có vẻ nhanh hơn thuật toán vũ phu, nhưng thật khó để tôi nghĩ ra các ví dụ đơn giản về điều này. Thay vào đó, tôi sẽ đưa ra các phép đo thực nghiệm
Khi làm việc với các thuật toán phức tạp như thế này, tôi rất dễ mắc lỗi. Để giảm bớt lo lắng rằng tôi đã mắc lỗi với thuật toán cây k-d, tôi sẽ tạo dữ liệu thử nghiệm và đảm bảo rằng kết quả khớp với kết quả của thuật toán brute force
6[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
5Trước bài kiểm tra này, tôi đã chắc chắn rằng thuật toán brute force là đúng. Chạy thử nghiệm này khiến tôi tự tin rằng thuật toán cây k-d của tôi cũng đúng
Tôi tạo một số dữ liệu thử nghiệm và sử dụng mô-đun cProfile để đo lường
8[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
90[3, 4]
[3, 4]
1Thuật toán brute force mất 26. 252 giây và thuật toán cây k-d mất 0. 231 giây [nhanh hơn 100 lần]
Trong bài đăng tuần này, bạn đã học cách giải "Bài toán hàng xóm gần nhất" một cách hiệu quả bằng cách sử dụng cây k-d [một loại chỉ số không gian]. Cây K-d cho phép bạn truy vấn hiệu quả các tập dữ liệu không gian lớn để tìm các điểm gần nhau. Cây K-d và các chỉ số không gian khác được sử dụng trong cơ sở dữ liệu để tối ưu hóa truy vấn
thách thức của tôi với bạn
Tôi đã viết một bài trước, "Xây dựng công cụ dòng lệnh để mô phỏng sự lây lan của nhiễm trùng", hướng dẫn bạn cách xây dựng mô phỏng lây nhiễm trong dân số
Xác định xem một người nhạy cảm có bị nhiễm bệnh hay không cần phải tìm người bị nhiễm bệnh gần nhất. Thuật toán trong bài đăng đó được sử dụng để tìm một người bị nhiễm bệnh thân thiết là thuật toán vũ phu
Thách thức của tôi đối với bạn là thay thế thuật toán vũ phu trong trình mô phỏng lây nhiễm bằng thuật toán cây k-d mà chúng tôi đã xây dựng trong bài đăng này
Nếu bạn thích bài đăng tuần này, hãy chia sẻ nó với bạn bè của bạn và theo dõi bài đăng tuần tới. Gặp bạn sau