ค้นหาเพื่อนบ้านลำดับที่ 1 ได้อย่างมีประสิทธิภาพ 200k polygons


14

สำหรับกลุ่มบล็อกการสำรวจสำมะโนประชากร 208,781 ทุกกลุ่มฉันต้องการดึงข้อมูลรหัสประจำตัว FIPS ของเพื่อนบ้านลำดับที่ 1 ทั้งหมด ฉันมีการดาวน์โหลดขอบเขตไทเกอร์ทั้งหมดและรวมเป็น 1GB เชพไฟล์เดียว

ฉันลองใช้สคริปต์ ArcPython ที่ใช้ SelectLayerByLocation สำหรับ BOUNDARY_TOUCHES ที่แกนกลาง แต่ใช้เวลามากกว่า 1 วินาทีสำหรับแต่ละกลุ่มบล็อกซึ่งช้ากว่าที่ฉันต้องการ นี่คือแม้หลังจากที่ฉัน จำกัด การค้นหา SelectLayerByLocation เพื่อบล็อกกลุ่มในสถานะเดียวกัน ฉันพบสคริปต์นี้แต่ยังใช้ SelectLayerByLocation ภายในเพื่อให้ไม่เร็วขึ้น

การแก้ปัญหาไม่จำเป็นต้องเป็นแบบ Arc - ฉันเปิดให้แพคเกจอื่น ๆ แม้ว่าฉันจะเขียนโค้ดด้วย Python ได้สบาย


2
ตั้งแต่เวอร์ชั่น 9.3 มีเครื่องมือในกล่องเครื่องมือ Spatial Statistics เพื่อทำสิ่งนี้ เริ่มต้นที่ 10.0 พวกเขามีประสิทธิภาพมาก ฉันจำได้ว่าเรียกใช้การดำเนินการที่คล้ายกันในรูปร่างไฟล์ที่มีขนาดใกล้เคียงกัน ( บล็อคทั้งหมดภายในหนึ่งสถานะ) และเสร็จสิ้นภายใน 30 นาที 15 จากนั้นสำหรับดิสก์ I / O - และนี่เป็นสองปีที่ผ่านมาบนเครื่องที่ช้ากว่ามาก รหัสแหล่ง Python นั้นสามารถเข้าถึงได้เช่นกัน
whuber

คุณใช้เครื่องมือประมวลผลเชิงพื้นที่ใดในสถิติเชิงพื้นที่
dmahr

1
ฉันลืมชื่อของมัน มันเป็นพิเศษสำหรับการสร้างตารางของความสัมพันธ์เพื่อนบ้านรูปหลายเหลี่ยม ระบบความช่วยเหลือสนับสนุนให้คุณสร้างตารางนี้ก่อนเรียกใช้เครื่องมือสถิติเชิงพื้นที่ตามเพื่อนบ้านเพื่อให้เครื่องมือไม่จำเป็นต้องคำนวณข้อมูลนี้ใหม่ได้ทันทีทุกครั้งที่ทำงาน ข้อ จำกัด ที่สำคัญอย่างน้อยในเวอร์ชัน 9.x คือเอาต์พุตอยู่ในรูปแบบ. dbf สำหรับรูปร่างไฟล์อินพุตขนาดใหญ่ที่ไม่สามารถใช้งานได้ซึ่งในกรณีนี้คุณต้องแยกการดำเนินการออกเป็นชิ้น ๆ หรือแฮ็คโค้ด Python เพื่อส่งออกในรูปแบบที่ดีกว่า
whuber


ใช่แค่นั้นแหละ รหัส Python ใช้ประโยชน์จากความสามารถ ArcGIS ภายในอย่างเต็มที่ (ซึ่งใช้ดัชนีเชิงพื้นที่) ทำให้อัลกอริทึมค่อนข้างเร็ว
whuber

คำตอบ:


3

หากคุณสามารถเข้าถึง ArcGIS 10.2 สำหรับเดสก์ท็อปหรือก่อนหน้านี้ได้ฉันคิดว่าเครื่องมือPolygon Neighbor (Analysis)ซึ่ง:

สร้างตารางที่มีสถิติโดยยึดตามรูปหลายเหลี่ยมแบบต่อเนื่องกัน (ทับซ้อน, ขอบพ้องกันหรือโหนด)

เพื่อนบ้านรูปหลายเหลี่ยม

อาจทำให้งานนี้ง่ายขึ้นมากในขณะนี้


ขอบคุณ PolyGeo ฉันได้อัปเดตคำตอบที่ยอมรับแล้วเพื่อให้เครื่องมือรูปหลายเหลี่ยมเพื่อนบ้านได้รับการเปิดเผยมากขึ้น มันมีประสิทธิภาพมากกว่าวิธี Python แบบแมนนวลถึงแม้ว่าฉันไม่แน่ใจว่าการเปรียบเทียบความสามารถในการปรับขนาดกับชุดข้อมูลขนาดใหญ่
dmahr

ขณะนี้ฉันใช้ 10.3 และมันล้มเหลวใน shapefile ของฉันด้วยบล็อกสำรวจสำมะโนประชากร ~ 300K
soandos

@soos ดูเหมือนว่ามันอาจจะคุ้มค่าที่จะทำการวิจัย / ถามคำถามใหม่
PolyGeo

8

สำหรับการแก้ปัญหาการหลีกเลี่ยง ArcGIS ใช้pysal คุณสามารถรับน้ำหนักได้โดยตรงจาก shapefiles โดยใช้:

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

หรือ

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

มุ่งหน้าไปที่เอกสารสำหรับข้อมูลเพิ่มเติม


3

เพียงแค่อัปเดต หลังจากทำตามคำแนะนำของ Whuber ฉันพบว่า Generate Spatial Weights Matrix ใช้ Python ลูปและพจนานุกรมเพื่อกำหนดเพื่อนบ้าน ฉันทำซ้ำกระบวนการด้านล่าง

ส่วนแรกวนซ้ำทุกจุดสุดยอดของทุกกลุ่มบล็อก มันสร้างพจนานุกรมที่มีพิกัดจุดสุดยอดเป็นกุญแจและรายการของรหัสกลุ่มบล็อกที่มีจุดสุดยอดที่พิกัดนั้นเป็นค่า โปรดทราบว่านี่ต้องใช้ชุดข้อมูลที่เป็นระเบียบเรียบร้อยเนื่องจากชุดข้อมูลจุดยอด / จุดยอดที่สมบูรณ์แบบเท่านั้นที่จะทำการลงทะเบียนเป็นความสัมพันธ์กับเพื่อนบ้าน โชคดีที่รูปร่างบล็อกกลุ่ม TIGER ของ Census Bureau นั้นใช้ได้ในเรื่องนี้

ส่วนที่สองจะวนซ้ำทุกจุดสุดยอดของทุกกลุ่มบล็อกอีกครั้ง มันสร้างพจนานุกรมที่มี ID กลุ่มบล็อกเป็นคีย์และ ID เพื่อนบ้านของกลุ่มบล็อกนั้นเป็นค่า

# 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

ในการเข้าใจย้อนหลังฉันรู้ว่าฉันสามารถใช้วิธีการที่แตกต่างกันสำหรับส่วนที่สองที่ไม่จำเป็นต้องวนลูปผ่าน Shapefile อีกครั้ง แต่นี่คือสิ่งที่ฉันใช้และมันใช้งานได้ดีแม้ในกลุ่มบล็อก 1000 ครั้ง ฉันไม่ได้ลองทำกับทั้งประเทศสหรัฐอเมริกา แต่มันสามารถดำเนินการสำหรับทั้งรัฐ


2

ทางเลือกที่อาจจะมีการใช้ PostgreSQL และPostGIS ฉันถามคำถามสองสามข้อเกี่ยวกับวิธีการคำนวณที่คล้ายกันในเว็บไซต์นี้:

ฉันพบว่ามีเส้นโค้งการเรียนรู้ที่สูงชันเพื่อหาว่าชิ้นส่วนต่าง ๆ ของซอฟต์แวร์เข้ากันได้อย่างไร แต่ฉันพบว่ามันยอดเยี่ยมสำหรับการคำนวณบนชั้นเวกเตอร์ขนาดใหญ่ ฉันใช้การคำนวณเพื่อนบ้านที่ใกล้ที่สุดกับรูปหลายเหลี่ยมหลายล้านและมันก็เทียบได้กับ ArcGIS อย่างรวดเร็ว


1

มีเพียงความคิดเห็นบางส่วน ... วิธี esri / ArcGIS ปัจจุบันใช้พจนานุกรมเพื่อเก็บข้อมูล แต่การคำนวณหลักจะทำใน C ++ โดยใช้ Polygon Neighbor Tool เครื่องมือนี้สร้างตารางที่มีข้อมูลความสัมพันธ์เช่นเดียวกับผู้เข้าร่วมเพิ่มเติมเช่นความยาวของขอบเขตที่แชร์ คุณสามารถใช้เครื่องมือสร้างน้ำหนักเมทริกซ์ Spatial หากคุณต้องการจัดเก็บและใช้ข้อมูลซ้ำแล้วซ้ำอีก นอกจากนี้คุณยังสามารถใช้ฟังก์ชั่นนี้ใน WeightsUtilities เพื่อสร้างพจนานุกรม [เข้าถึงแบบสุ่ม] ด้วยข้อมูลความต่อเนื่อง:

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

โดยที่ inputFC = คลาสคุณลักษณะรูปหลายเหลี่ยมชนิดใด ๆ masterField คือฟิลด์ "unique ID" ของจำนวนเต็มและ contiguityType ใน {"ROOK", "QUEEN"}

มีความพยายามที่ esri ที่จะข้ามส่วนที่เป็นตารางสำหรับผู้ใช้ Python และตรงไปที่ตัววนซ้ำซึ่งจะทำให้การใช้งานหลายกรณีเร็วขึ้น PySAL และแพคเกจ spdep ใน R เป็นทางเลือกที่ยอดเยี่ยม [ดูคำตอบของ Radek] ฉันคิดว่าคุณจะต้องใช้ shapefiles เป็นรูปแบบข้อมูลในแพ็คเกจเหล่านี้ซึ่งอยู่ในรูปแบบ w / นี่กระทู้รูปแบบการป้อนข้อมูล ไม่แน่ใจว่าพวกเขาจัดการกับรูปหลายเหลี่ยมที่ทับซ้อนกันและรูปหลายเหลี่ยมภายในรูปหลายเหลี่ยมได้อย่างไร สร้าง SWM เช่นเดียวกับฟังก์ชั่นที่ฉันอธิบายจะนับความสัมพันธ์เชิงพื้นที่เหล่านั้นเป็นเพื่อนบ้าน "ROOK" และ "QUEEN"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.