Kdtree chèn python

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ựng

import 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ày

[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
0
[ [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"

[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
2
{[3, 4]: [3, 5],
 [5, 1]: [4, 1],
 [7, 3]: [4, 1],
 [8, 9]: [3, 5],
 [10, 1]: [4, 1],
 [3, 3]: [3, 2]}
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
4
[ [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

[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
6
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
5

Trướ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

[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
8
[ [3, 4], [5, 1], [7, 3], [8, 9], [10, 1], [3, 3] ]
9
[3, 4]
0
[3, 4]
1

Thuậ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

Chủ Đề