200k poligonun birinci dereceden komşularını verimli bir şekilde bulma


14

208.781 Sayım bloğu grubunun her biri için, tüm 1. derece komşularının FIPS kimliklerini almak istiyorum. Tüm TIGER sınırlarını indirip tek bir 1GB şekil dosyasına dönüştürdüm.

Özünde BOUNDARY_TOUCHES için SelectLayerByLocation kullanan bir ArcPython betiği denedim, ancak istediğimden daha yavaş olan her blok grubu için 1 saniyeden fazla sürüyor. Bu, aynı durumdaki grupları engellemek için SelectLayerByLocation aramasını sınırlandırdıktan sonra bile. Bu komut dosyasını buldum , ancak aynı zamanda dahili olarak SelectLayerByLocation kullanıyor, bu yüzden daha hızlı değil.

Çözüm Arc tabanlı olmak zorunda değil - Python ile en rahat kodlama yapmama rağmen diğer paketlere açığım.


2
Sürüm 9.3'ten bu yana, Uzamsal İstatistikler araç kutusunda bunu yapmak için araçlar vardır. 10.0'dan başlayarak çok verimlidirler. Benzer bir işlemin benzer boyutta bir şekil dosyasında ( bir durum içindeki tüm bloklar ) çalıştırıldığını hatırlıyorum ve 30 dakika içinde tamamlandı, 15 tanesi sadece disk G / Ç için - ve bu iki yıl önce çok daha yavaş bir makinede yapıldı. Python kaynak koduna da erişilebilir.
whuber

Mekansal İstatistiklerde hangi coğrafi işleme aracını kullandınız?
dmahr

1
Adını unuttum; özellikle çokgen komşu ilişkileri tablosu oluşturmak içindir. Yardım sistemi , komşu tabanlı uzamsal istatistik araçlarından herhangi birini çalıştırmadan önce bu tabloyu oluşturmaya teşvik eder , böylece araçların her çalıştıklarında bu bilgileri anında yeniden hesaplamaları gerekmez. En azından 9.x sürümünde önemli bir sınırlama, çıktının .dbf biçiminde olmasıdır. Çalışmayan büyük bir giriş şekli dosyası için, işlemi daha iyi bir biçimde çıkarmak için işlemi parçalara ayırmanız veya Python kodunu hacklemeniz gerekir.
whuber


Evet, bu o. Python kodu, dahili ArcGIS yeteneklerinden (mekansal dizinler kullanan) tam olarak yararlanır ve algoritmayı oldukça hızlı hale getirir.
whuber

Yanıtlar:


3

Masaüstü için ArcGIS 10.2'ye veya muhtemelen daha önce erişime sahipseniz, Poligon Komşuları (Analiz) aracını düşünüyorum :

Çokgen bitişikliğine (çakışmalar, çakışan kenarlar veya düğümler) dayalı istatistiklere sahip bir tablo oluşturur.

Çokgen komşuları

bu görevi artık çok daha kolay hale getirebilir.


Teşekkürler PolyGeo. Çokgen Komşular aracının biraz daha fazla poz alması için kabul edilen cevabı güncelledim. El ile Python tabanlı yöntemimden kesinlikle daha sağlam, ancak büyük veri kümeleriyle ölçeklenebilirliğin nasıl karşılaştırıldığından emin değilim.
dmahr

Şu anda 10.3 kullanıyorum ve ~ 300K nüfus sayımı bloklarıyla şekil dosyamda başarısız oluyor.
soandos

@soandos Yeni bir soru olarak araştırmaya / sormaya değebilir gibi görünüyor.
PolyGeo

8

ArcGIS'ten kaçınan bir çözüm için pysal kullanın . Ağırlıkları doğrudan şekil dosyalarından alabilirsiniz:

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

veya

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

İçin baş docs fazla bilgi için.


3

Sadece bir güncelleme. Whuber'ın tavsiyelerini izledikten sonra, Mekansal Ağırlık Üret Matrisinin komşuları belirlemek için sadece Python döngüleri ve sözlüklerini kullandığını gördüm. Aşağıdaki işlemi tekrarladım.

İlk bölüm, her blok grubunun her köşesinde dolaşır. Anahtar olarak tepe koordinatlarına sahip bir sözlük ve değer olarak bu koordinatta tepe noktasına sahip blok grubu kimliklerinin bir listesini oluşturur. Yalnızca mükemmel tepe / tepe noktası çakışması komşu bir ilişki olarak kaydedileceğinden, bunun topolojik olarak düzgün bir veri kümesi gerektirdiğini unutmayın. Neyse ki Sayım Bürosu'nun TIGER blok grubu şekil dosyaları bu açıdan sorun yaratmaz.

İkinci kısım, her blok grubunun her köşesinden tekrar geçer. Anahtarlar olarak blok grubu kimlikleri ve değerler olarak grubun komşu kimlikleri ile bir sözlük oluşturur.

# 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

Geriye dönüp baktığımda, ikinci kısım için şekil dosyasının içinden tekrar geçmeyi gerektirmeyen farklı bir yöntem kullanabileceğimin farkındayım. Ama bu benim kullandığım şey ve bir seferde 1000'li blok grupları için bile oldukça iyi çalışıyor. Bunu tüm ABD ile yapmayı denemedim, ancak bütün bir devlet için idam edilebilir.


2

Bir alternatif PostgreSQL ve PostGIS kullanmak olabilir . Bu sitede benzer hesaplamaları nasıl yapacağınız hakkında birkaç soru sordum:

Yazılımın çeşitli parçalarının nasıl bir araya geldiğini anlamak için dik bir öğrenme eğrisi buldum, ancak büyük vektör katmanlarında hesaplamalar yapmak için harika buldum. Milyonlarca çokgen üzerinde en yakın komşu hesaplamaları yaptım ve ArcGIS ile karşılaştırıldığında hızlıydı.


1

Sadece bazı yorumlar ... esri / ArcGIS yöntemi şu anda bilgileri tutmak için sözlükler kullanıyor ancak çekirdek hesaplamalar C ++ 'da Çokgen Komşular Aracı kullanılarak yapılıyor. Bu araç, bitişiklik bilgilerinin yanı sıra paylaşılan sınırın uzunluğu gibi isteğe bağlı davetiyeleri içeren bir Tablo oluşturur. Bilgileri tekrar tekrar depolamak ve daha sonra tekrar kullanmak istiyorsanız, Uzamsal Ağırlık Oluştur Matris Aracını kullanabilirsiniz. Bu işlevi WeightsUtilities içinde bitişiklik bilgileriyle bir sözlük [rastgele erişim] oluşturmak için de kullanabilirsiniz:

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

Burada inputFC = herhangi bir çokgen özelliği sınıfı, masterField {"ROOK", "QUEEN"} içindeki tamsayıların ve contiguityType'ın "benzersiz ID" alanıdır.

Esri'de Python kullanıcıları için tablo biçimini atlamak ve doğrudan birçok kullanım örneğini çok daha hızlı hale getirecek bir yineleyiciye gitmek için çabalar var. PySAL ve R'deki spdep paketi harika alternatiflerdir [ radek'in cevabına bakınız ] . Bence bu konu giriş formatı ile uyum içinde olan bu paketlerde veri biçimi olarak shapefiles kullanmanız gerekir. Çakışan çokgenlerle ve çokgenler içindeki çokgenlerle nasıl başa çıktıklarından emin değiller. SWM oluştur ve tanımladığım fonksiyon bu uzamsal ilişkileri "ROOK" VE "QUEEN" Komşuları olarak sayar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.