Tìm kiếm hiệu quả hàng xóm thứ 1 của 200k đa giác


14

Đối với mỗi một trong số 208.781 nhóm khối Điều tra dân số, tôi muốn truy xuất ID ID của tất cả các hàng xóm thứ tự thứ nhất của nó. Tôi có tất cả các ranh giới TIGER được tải xuống và hợp nhất thành một shapefile 1GB duy nhất.

Tôi đã thử một tập lệnh ArcPython sử dụng SelectLayerByLocation cho BOUNDARY_TOUCHES ở lõi của nó, nhưng mất hơn 1 giây cho mỗi nhóm khối chậm hơn tôi muốn. Điều này thậm chí sau khi tôi giới hạn tìm kiếm SelectLayerByLocation để chặn các nhóm trong cùng trạng thái. Tôi đã tìm thấy tập lệnh này , nhưng nó cũng sử dụng SelectLayerByLocation trong nội bộ để nó không nhanh hơn.

Giải pháp không nhất thiết phải dựa trên Arc - Tôi đang mở các gói khác, mặc dù tôi cảm thấy thoải mái nhất khi viết mã bằng Python.


2
Kể từ phiên bản 9.3, đã có các công cụ trong hộp công cụ Thống kê không gian để thực hiện việc này. Bắt đầu từ 10.0, chúng rất hiệu quả. Tôi nhớ lại việc chạy một hoạt động tương tự trên một shapefile có kích thước tương đương (tất cả các khối trong một trạng thái) và nó đã hoàn thành trong 30 phút, 15 trong số đó chỉ dành cho đĩa I / O - và đây là hai năm trước trên một máy chậm hơn nhiều. Mã nguồn Python cũng có thể truy cập được.
whuber

Bạn đã sử dụng công cụ xử lý địa lý nào trong Thống kê không gian?
dmahr

1
Tôi quên tên của nó; nó đặc biệt để tạo một bảng các mối quan hệ láng giềng đa giác. Hệ thống trợ giúp khuyến khích bạn tạo bảng này trước khi chạy bất kỳ công cụ thống kê không gian dựa trên hàng xóm nào, để các công cụ không phải tính toán lại thông tin này mỗi khi chúng chạy. Một hạn chế đáng kể, ít nhất là trong phiên bản 9.x, là đầu ra ở định dạng .dbf. Đối với một shapefile đầu vào lớn sẽ không hoạt động, trong trường hợp đó, bạn phải chia thao tác thành từng mảnh hoặc hack mã Python để xuất ra ở định dạng tốt hơn.
whuber


Vâng, đó là nó. Mã Python khai thác triệt để các khả năng ArcGIS nội bộ (sử dụng các chỉ mục không gian), làm cho thuật toán khá nhanh.
whuber

Câu trả lời:


3

Nếu bạn có quyền truy cập ArcGIS 10.2 cho Máy tính để bàn, hoặc có thể sớm hơn, thì tôi nghĩ rằng công cụ Polygon Neighbor (Phân tích) :

Tạo một bảng với các số liệu thống kê dựa trên sự liên tục đa giác (chồng chéo, cạnh trùng hoặc nút).

Hàng xóm đa giác

có thể làm cho nhiệm vụ này dễ dàng hơn nhiều bây giờ.


Cảm ơn, PolyGeo. Tôi đã cập nhật câu trả lời được chấp nhận để công cụ Hàng xóm đa giác được hiển thị nhiều hơn một chút. Nó chắc chắn mạnh hơn phương pháp dựa trên Python thủ công của tôi, mặc dù tôi không chắc khả năng mở rộng với các bộ dữ liệu lớn so sánh như thế nào.
dmahr

Tôi hiện đang sử dụng 10.3 và nó không thành công trên shapefile của tôi với các khối điều tra dân số ~ 300K.
soandos 17/05/2015

@soandos Nghe có vẻ đáng để nghiên cứu / hỏi như một câu hỏi mới.
PolyGeo

8

Đối với một giải pháp tránh ArcGIS, sử dụng pysal . Bạn có thể lấy trọng lượng trực tiếp từ shapefiles bằng cách sử dụng:

w = pysal.rook_from_shapefile("../pysal/examples/columbus.shp")

hoặc là

w = pysal.queen_from_shapefile("../pysal/examples/columbus.shp")

Đầu cho các tài liệu để biết thêm.


3

Chỉ là một bản cập nhật. Sau khi làm theo lời khuyên của Whuber, tôi thấy rằng Ma trận trọng lượng không gian đơn giản chỉ sử dụng các vòng lặp và từ điển Python để xác định hàng xóm. Tôi đã sao chép quá trình dưới đây.

Phần đầu tiên lặp qua mọi đỉnh của mọi nhóm khối. Nó tạo ra một từ điển với tọa độ đỉnh là các khóa và danh sách ID nhóm khối có đỉnh ở tọa độ đó làm giá trị. Lưu ý rằng điều này đòi hỏi một bộ dữ liệu gọn gàng về mặt tôpô, vì chỉ có chồng chéo đỉnh / đỉnh hoàn hảo mới đăng ký như một mối quan hệ láng giềng. May mắn thay, các shapefile nhóm khối điều tra của Cục điều tra dân số là ổn về vấn đề này.

Phần thứ hai lặp lại qua mọi đỉnh của mỗi nhóm khối một lần nữa. Nó tạo ra một từ điển với ID nhóm khối làm khóa và ID của hàng xóm của nhóm đó làm giá trị.

# Create dictionary of vertex coordinate : [...,IDs,...]
BlockGroupVertexDictionary = {}
BlockGroupCursor = arcpy.SearchCursor(BlockGroups.shp)
BlockGroupDescription = arcpy.Describe(BlockGroups.shp)
BlockGroupShapeFieldName = BlockGroupsDescription.ShapeFieldName
#For every block group...
for BlockGroupItem in BlockGroupCursor :
    BlockGroupID = BlockGroupItem.getValue("BKGPIDFP00")
    BlockGroupFeature = BlockGroupItem.getValue(BlockGroupShapeFieldName)
    for BlockGroupPart in BlockGroupFeature:
        #For every vertex...
        for BlockGroupPoint in BlockGroupPart:
            #If it exists (and isnt empty interior hole signifier)...
            if BlockGroupPoint:
                #Create string version of coordinate
                PointText = str(BlockGroupPoint.X)+str(BlockGroupPoint.Y)
                #If coordinate is already in dictionary, append this BG's ID
                if PointText in BlockGroupVertexDictionary:
                    BlockGroupVertexDictionary[PointText].append(BlockGroupID)
                #If coordinate is not already in dictionary, create new list with this BG's ID
                else:
                    BlockGroupVertexDictionary[PointText] = [BlockGroupID]
del BlockGroupItem
del BlockGroupCursor


#Create dictionary of ID : [...,neighbors,...]
BlockGroupNeighborDictionary = {}
BlockGroupCursor = arcpy.SearchCursor(BlockGroups.shp)
BlockGroupDescription = arcpy.Describe(BlockGroups.shp)
BlockGroupShapeFieldName = BlockGroupDescription.ShapeFieldName
#For every block group
for BlockGroupItem in BlockGroupCursor:
    ListOfBlockGroupNeighbors = []
    BlockGroupID = BlockGroupItem.getValue("BKGPIDFP00")
    BlockGroupFeature = BlockGroupItem.getValue(BlockGroupShapeFieldName)
    for BlockGroupPart in BlockGroupFeature:
        #For every vertex
        for BlockGroupPoint in BlockGroupPart:
            #If it exists (and isnt interior hole signifier)...
            if BlockGroupPoint:
                #Create string version of coordinate
                PointText = str(BlockGroupPoint.X)+str(BlockGroupPoint.Y)
                if PointText in BlockGroupVertexDictionary:
                    #Get list of block groups that have this point as a vertex
                    NeighborIDList = BlockGroupVertexDictionary[PointText]
                    for NeighborID in NeighborIDList:
                        #Don't add if this BG already in list of neighbors
                        if NeighborID in ListOfBGNeighbors:
                            pass
                        #Add to list of neighbors (as long as its not itself)
                        elif NeighborID != BlockGroupID:
                            ListOfBGNeighbors.append(NeighborID)
    #Store list of neighbors in blockgroup object in dictionary
    BlockGroupNeighborDictionary[BlockGroupID] = ListOfBGNeighbors

del BlockGroupItem
del BlockGroupCursor
del BlockGroupVertexDictionary

Nhìn lại, tôi nhận ra rằng tôi có thể đã sử dụng một phương pháp khác cho phần thứ hai mà không yêu cầu lặp lại thông qua shapefile một lần nữa. Nhưng đây là những gì tôi đã sử dụng và nó hoạt động khá tốt ngay cả với 1000 nhóm khối cùng một lúc. Tôi đã không thử làm điều đó với toàn bộ Hoa Kỳ, nhưng nó có thể thực thi cho toàn bộ tiểu bang.


2

Một cách khác có thể là sử dụng PostgreSQL và PostGIS . Tôi đã hỏi một vài câu hỏi về cách thực hiện các tính toán tương tự trên trang web này:

Tôi thấy ở đó có một đường cong học tập dốc để tìm ra cách các phần mềm khác nhau khớp với nhau, nhưng tôi thấy thật tuyệt vời khi thực hiện các phép tính trên các lớp vectơ lớn. Tôi đã chạy một số tính toán lân cận gần nhất trên hàng triệu đa giác và nó đã nhanh chóng so với ArcGIS.


1

Chỉ cần một số nhận xét ... phương pháp esri / ArcGIS hiện đang sử dụng từ điển để lưu giữ thông tin nhưng các tính toán cốt lõi được thực hiện trong C ++ bằng Công cụ hàng xóm đa giác. Công cụ này tạo ra một Bảng chứa thông tin liên tục cũng như các tùy chọn tùy chỉnh như độ dài của ranh giới được chia sẻ. Bạn có thể sử dụng Công cụ Ma trận Trọng lượng Không gian Tạo nếu bạn muốn lưu trữ và sau đó sử dụng lại thông tin nhiều lần. Bạn cũng có thể sử dụng chức năng này trong WeightsUtilities để tạo từ điển [truy cập ngẫu nhiên] với thông tin liên tục:

contDict = polygonNeighborDict(inputFC, masterField, contiguityType = "ROOK")

trong đó inputFC = bất kỳ loại lớp tính năng đa giác nào, masterField là trường "ID duy nhất" của số nguyên và contiguityType trong {"ROOK", "QUEEN"}.

Có những nỗ lực tại esri để bỏ qua khía cạnh dạng bảng cho người dùng Python và đi thẳng đến một trình vòng lặp, điều này sẽ khiến nhiều trường hợp sử dụng nhanh hơn rất nhiều. PySAL và gói spdep trong R là những lựa chọn thay thế tuyệt vời [xem câu trả lời của radek] . Tôi nghĩ rằng bạn được yêu cầu sử dụng shapefiles làm định dạng dữ liệu trong các gói này được điều chỉnh theo định dạng đầu vào của chủ đề này. Không chắc chắn làm thế nào họ đối phó với đa giác chồng chéo cũng như đa giác trong đa giác. Tạo SWM cũng như chức năng mà tôi đã mô tả sẽ tính các mối quan hệ không gian đó là "ROOK" và "QUEEN" Hàng xóm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.