Membagi poligon menjadi * n * jumlah grup dengan jumlah yang sama dengan ArcPy?

10

Salah satu tugas saya untuk bekerja adalah membagi paket menjadi beberapa kelompok. Grup-grup ini akan digunakan oleh agen untuk berbicara dengan pemilik properti. Tujuannya adalah untuk memudahkan pekerjaan agen dengan mengelompokkan paket yang berdekatan satu sama lain, serta membagi paket menjadi jumlah yang sama sehingga pekerjaan didistribusikan secara merata. Jumlah agen dapat berfluktuasi dari pasangan menjadi 10+.

Saat ini saya melakukan tugas ini secara manual, tetapi ingin mengotomatiskan proses jika memungkinkan. Saya telah menjelajahi berbagai alat ArcGIS, tetapi sepertinya tidak ada yang sesuai dengan kebutuhan saya. Saya mencoba skrip (dalam python) yang menggunakan near_analysisdan memilih poligon, tetapi ini agak acak dan membutuhkan selamanya untuk mencapai hasil semi-benar yang kemudian membutuhkan saya lebih lama untuk memperbaikinya daripada jika saya hanya melakukan semuanya secara manual dari awal.

Apakah ada metode yang dapat diandalkan untuk mengotomatisasi tugas ini?

Contoh hasil (semoga tanpa pembagian yang kita lihat berwarna kuning):

Paket yang Dibagi

Emil Brundage
sumber
Sudahkah Anda melihat analisis alokasi lokasi? help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/…
floem
Sudahkah Anda mencoba Analisis Pengelompokan (Statistik Spasial)?
FelixIP
Saya juga memposting kode palsu dari prosedur aktual yang saya gunakan, lihat apakah itu dapat membantu gis.stackexchange.com/questions/123289/...
FelixIP
@ crmackey Saya menghargai tautan ke jawaban saya, tapi saya tidak yakin bagaimana Anda bisa mengubah kode tertaut (membelah poligon) agar sesuai dengan masalah ini (pengelompokan poligon).
Floem

Jawaban:

4

Set asli:

masukkan deskripsi gambar di sini

Buat pseudo-copy (seret CNTRL di TOC) dari itu dan buat spasial satu dengan banyak orang dengan klon. Dalam hal ini saya menggunakan jarak 500m. Tabel output:

masukkan deskripsi gambar di sini

  1. Hapus catatan dari tabel ini tempat PAR_ID = PAR_ID_1 - mudah.

  2. Iterasi melalui tabel dan hapus rekaman di mana (PAR_ID, PAR_ID_1) = (PAR_ID_1, PAR_ID) dari semua catatan di atasnya. Tidak mudah, gunakan acrpy.

Hitung centroid tangkapan (UniqID = PAR_ID). Mereka adalah node atau jaringan. Hubungkan mereka dengan garis menggunakan tabel bergabung spasial. Ini adalah topik terpisah yang pasti dibahas di suatu tempat di forum ini.

masukkan deskripsi gambar di sini

Script di bawah ini menganggap bahwa tabel node terlihat seperti itu: masukkan deskripsi gambar di sini

di mana MUID berasal dari bidang, P2013 adalah bidang untuk diringkas. Dalam hal ini = 1 untuk penghitungan saja. [rcvnode] - output skrip untuk menyimpan ID grup sama dengan NODEREC dari node pertama dalam grup / cluster yang ditentukan.

Tautan struktur tabel dengan bidang-bidang penting yang disorot

masukkan deskripsi gambar di sini

Times menyimpan link / edge weight, yaitu biaya perjalanan dari node ke node. Sama dengan 1 dalam hal ini sehingga biaya perjalanan ke semua tetangga adalah sama. [fi] dan [ti] adalah nomor urut dari node yang terhubung. Untuk mengisi tabel ini, cari di forum ini tentang cara menetapkan dari dan ke simpul yang akan ditautkan.

Script disesuaikan untuk meja kerja saya sendiri mxd. Harus dimodifikasi, hardcoded dengan penamaan bidang dan sumber Anda:

import arcpy, traceback, os, sys,time
import itertools as itt
scriptsPath=os.path.dirname(os.path.realpath(__file__))
os.chdir(scriptsPath)
import COMMON
sys.path.append(r'C:\Users\felix_pertziger\AppData\Roaming\Python\Python27\site-packages')
import networkx as nx
RATIO = int(arcpy.GetParameterAsText(0))

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
mxd = arcpy.mapping.MapDocument("CURRENT")
theT=COMMON.getTable(mxd)

TEMUKAN LAPANG NODES

theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)

DAPATKAN LAPIS LINKS

    theLinksLayer = COMMON.getInfoFromTable(theT,9)
    theLinksLayer = COMMON.isLayerExist(mxd,theLinksLayer)
    arcpy.SelectLayerByAttribute_management(theLinksLayer, "CLEAR_SELECTION")        
    linksFromI=COMMON.getInfoFromTable(theT,14)
    linksToI=COMMON.getInfoFromTable(theT,13)
    G=nx.Graph()
    arcpy.AddMessage("Adding links to graph")
    with arcpy.da.SearchCursor(theLinksLayer, (linksFromI,linksToI,"Times")) as cursor:
            for row in cursor:
                (f,t,c)=row
                G.add_edge(f,t,weight=c)
            del row, cursor
    pops=[]
    pops=arcpy.da.TableToNumPyArray(theNodesLayer,("P2013"))
    length0=nx.all_pairs_shortest_path_length(G)
    nNodes=len(pops)
    aBmNodes=[]
    aBig=xrange(nNodes)
    host=[-1]*nNodes
    while True:
            RATIO+=-1
            if RATIO==0:
                    break
            aBig = filter(lambda x: x not in aBmNodes, aBig)
            p=itt.combinations(aBig, 2)
            pMin=1000000
            small=[]
            for a in p:
                    S0,S1=0,0
                    for i in aBig:
                            p=pops[i][0]
                            p0=length0[a[0]][i]
                            p1=length0[a[1]][i]
                            if p0<p1:
                                    S0+=p
                            else:
                                    S1+=p
                    if S0!=0 and S1!=0:
                            sMin=min(S0,S1)                        
                            sMax=max(S0,S1)
                            df=abs(float(sMax)/sMin-RATIO)
                            if df<pMin:
                                    pMin=df
                                    aBest=a[:]
                                    arcpy.AddMessage('%s %i %i' %(aBest,sMax,sMin))
                            if df<0.005:
                                    break
            lSmall,lBig,S0,S1=[],[],0,0
            arcpy.AddMessage ('Ratio %i' %RATIO)
            for i in aBig:
                    p0=length0[aBest[0]][i]
                    p1=length0[aBest[1]][i]
                    if p0<p1:
                            lSmall.append(i)
                            S0+=p0
                    else:
                            lBig.append(i)
                            S1+=p1
            if S0<S1:
                    aBmNodes=lSmall[:]
                    for i in aBmNodes:
                            host[i]=aBest[0]
                    for i in lBig:
                            host[i]=aBest[1]
            else:
                    aBmNodes=lBig[:]
                    for i in aBmNodes:
                            host[i]=aBest[1]
                    for i in lSmall:
                            host[i]=aBest[0]

    with arcpy.da.UpdateCursor(theNodesLayer, "rcvnode") as cursor:
            i=0
            for row in cursor:
                    row[0]=host[i]
                    cursor.updateRow(row)
                    i+=1

            del row, cursor
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

Contoh output untuk 6 grup:

masukkan deskripsi gambar di sini

Anda akan memerlukan paket situs NETWORKX http://networkx.github.io/documentation/development/install.html

Script mengambil jumlah cluster yang diperlukan sebagai parameter (6 pada contoh di atas). Ia menggunakan tabel simpul dan tautan untuk membuat grafik dengan bobot / jarak tepi perjalanan yang sama (Times = 1). Itu mempertimbangkan kombinasi semua node dengan 2 dan menghitung total [P2013] dalam dua kelompok tetangga. Ketika rasio yang diperlukan tercapai, misalnya (6-1) / 1 pada iterasi pertama, dilanjutkan dengan target rasio yang dikurangi, yaitu 4, dll. Hingga 1. Titik awal sangat penting, jadi pastikan simpul 'ujung' Anda berada di atas dari tabel node Anda (pengurutan?) Lihat 3 grup pertama dalam contoh output. Ini membantu untuk menghindari 'pemotongan cabang' di setiap iterasi berikutnya.

Kustomisasi skrip untuk bekerja dari mxd:

  1. Anda tidak perlu mengimpor UMUM. Adalah hal saya sendiri, yang membaca tabel lingkungan saya sendiri, di manaNodesLayer, theLinksLayer, linksFromI, linksToI ditentukan. Ganti baris yang relevan dengan penamaan node dan lapisan tautan Anda sendiri.
  2. Perhatikan bahwa bidang P2013 dapat menyimpan apa pun, misalnya jumlah penyewa atau area parsel. Jika demikian, Anda dapat mengelompokkan poligon untuk menampung kira-kira jumlah orang yang sama dll.
FelixIP
sumber
Pada kenyataannya, simpul dan tautan hanyalah hal-hal visual. Tabel clean-up dari join spasial dapat dengan mudah mengganti tabel tautan, karena dari dan ke node sudah ditetapkan. Tabel poligon, dapat dengan mudah berfungsi sebagai tabel node, cukup tambahkan bidang ReceivingNode dan transfer nomor urut dari kembali ke 'tautan' [FromI] dan [ToI].
FelixIP
Ini terlihat bagus. Terima kasih banyak atas jawabannya. Bisakah Anda menjelaskan lebih banyak tentang mengapa, dan bukan hanya caranya? Komentar pada kode Anda akan sangat besar.
Emil Brundage
Ikuti hyperlink di komentar saya sebelumnya ke pertanyaan Anda. Saya sudah mencoba menjelaskan pendekatannya, jika ini yang dimaksud dengan 'mengapa'. Saya menarik komentar saya tentang pentingnya memulai simpul, karena setelah memposting jawaban untuk Q Anda, saya secara acak mengubah catatan agar mencoba untuk mematikan skrip. Tidak ada yang terjadi masih menghasilkan hasil yang masuk akal.
FelixIP
Untuk membersihkan tabel join spasial, cukup menghapus PAR_ID = PAR_ID_1, karena edge / tautan [0,2] dalam grafik NETWORKX yang tidak diarahkan sama dengan edge [2,0]. Saya dapat mengirim skrip yang diperbarui, tidak yakin apakah itu akan mempengaruhi reputasi saya
FelixIP
@EmilBrundage memeriksanya, mungkin membantu dengan pertanyaan mengapa gis.stackexchange.com/questions/165057/…
FelixIP
2

Anda harus menggunakan alat "Analisis Kelompok" untuk mencapai tujuan Anda. Alat ini adalah alat yang hebat dari kotak alat "statistik spasial" seperti yang ditunjukkan oleh @ phloem. Namun Anda harus menyesuaikan alat untuk beradaptasi dengan data dan masalah Anda. Saya membuat skenario serupa seperti yang Anda posting dan mendapatkan respons yang dekat dengan tujuan Anda.

Petunjuk: Menggunakan ArcGIS 10.2, ketika saya menjalankan alat, ia mengeluh tentang paket python yang hilang, "enam". Jadi, pastikan Anda memilikinya diinstal terlebih dahulu Tautan

Langkah:

  1. Tambahkan bidang ke kelas poligon Anda untuk menyimpan nilai unik
  2. Tambahkan bidang jenis Pendek lainnya dengan nama misalnya "SameGroup"
  3. Anda kalkulator bidang untuk menetapkan 1 ke bidang ini untuk semua baris. ubah saja satu baris menjadi 2. Bidang yang ditambahkan

  4. Tetapkan parameter alat "Analisis Kelompok" seperti ini: Analisis Kelompok

coba ubah parameter "Jumlah Tetangga" sesuai kebutuhan Anda.

Snapshots Hasil:

Contoh Masukan Poligon

Hasil Analisis Kelompok

Farid Cheraghi
sumber
2
Saya telah melihat Analisis Kelompok sebelumnya. Ini berkaitan dengan spasial, tetapi tidak dihitung sejauh yang saya tahu. Semua pengalaman saya dari membaca dokumentasi, melihat contoh Anda, dan melakukan tes saya sendiri tidak memungkinkan untuk dikelompokkan dengan jumlah poligon yang sama.
Emil Brundage
Mengapa Anda harus menyamakan kedudukan (di luar jalur untuk agen)? Tetapi jika kita menambahkan batasan itu lalu mengapa mengelompokkan (mengelompokkan) data berdasarkan hubungan spasial !?
Farid Cheraghi
1
Karena bos bilang begitu. Juga, meminimalkan waktu perjalanan.
Emil Brundage
1

pada dasarnya Anda menginginkan metode pengelompokan ukuran yang sama, sehingga Anda dapat mencari dengan kata-kata kunci ini di web. Bagi saya, ada jawaban yang bagus pada stats.SE dengan implementasi Python di salah satu jawaban. Jika Anda terbiasa dengan arcpy Anda harus dapat menggunakannya dengan data Anda.

Pertama-tama Anda perlu menghitung X dan Y dari centroid poligon Anda, kemudian Anda dapat memasukkan koordinat ini dalam skrip dan memperbarui tabel atribut mereka menggunakan kursor .da.

radouxju
sumber
Tautan yang Anda berikan sepertinya ada di jalur yang benar, tetapi pada dasarnya dalam bahasa yang saya tidak mengerti. Untuk skrip saya tidak tahu apa inputnya dan tidak bisa menguraikan kode apa pun untuk memahami apa yang sebenarnya terjadi. Ada sedikit penjelasan.
Emil Brundage
0

Hai, di sana saya punya masalah yang sama seperti ini sebelumnya, jadi saya sudah memberikannya, tidak pernah memulai lagi, tetapi hanya di sisi pencuri yang saya pikirkan

BENTUK INPUT

Bentuk input

Saya berpikir Anda bisa membuat jala pada bentuk input

langgai jala dengan irisan bentuk input Anda akan

masukan ke area

Anda kemudian dapat menghitung luas bidang-bidang ini di dalam poligon yang baru diproses

Di awal skrip Anda, area memasukkan poligon / jumlah yang sama dengan ukuran yang diinginkan

Anda kemudian akan membutuhkan cara untuk menghubungkan paket sehingga mereka menyadari yang berbatasan.

Kemudian Anda bisa pergi melalui kursor baris dari menyimpulkan paket

Peraturan sedang

* Ini berbagi perbatasan ke satu musim panas yang lalu * Itu belum dijumlahkan * Setelah melampaui nilai yang dihitung sebagai area yang sama, itu akan mundur dan ini akan menjadi grup * Proses akan mulai lagi * grup terakhir bisa menjadi jumlah paket yang tersisa

Saya pikir membangun hubungan antara paket mungkin menjadi hal yang rumit tetapi setelah ini selesai saya pikir itu mungkin untuk mengotomatiskannya

Jack Walker
sumber
Saya khawatir saya tidak mengerti apa hubungannya ini dengan masalah saya. Apa hubungannya dengan memotong poligon dengan jaring ikan dengan pengelompokan poligon secara spasial dan dengan jumlah yang sama? Anda tampaknya fokus pada area, bukan menghitung. Luas (ukuran) poligon paket bukan merupakan faktor. Terlepas dari seberapa besar atau kecil parsel itu, masih hanya satu pemilik properti untuk diajak bicara. Lihat contoh saya di mana merah adalah area pedesaan dan menyebar luas, sedangkan oranye adalah perkotaan dan mencakup area total yang jauh lebih kecil.
Emil Brundage
hai di sana Anda, maaf saya salah membaca pertanyaan Anda. Saya pikir posting radouxju bisa menjadi cara untuk pergi, tetapi tautannya sedikit berlebihan. Mengubah poligon menjadi poin tampak logis dan kemudian mengelompokkannya. Mungkin ada cara memperkenalkan sistem jalan sebagai jarak dari titik ke jalan dan titik berikutnya mungkin mendefinisikan elemen spasial
Jack Walker
0

Ini adalah solusi saya untuk event point. Tidak ada jaminan itu akan selalu berhasil ...

  1. Pada layer acara titik Anda (panggil layer1) tambahkan kolom untuk x (ganda), y (ganda), dan uniqueid (bilangan bulat panjang)
  2. Buka tabel atribut untuk layer 1. Hitung titik koordinat x untuk x, titik koordinat y untuk y, dan FID untuk id unik
  3. Menjalankan Alat Statistik Spasial> Memetakan Cluster> Analisis Pengelompokan
    • atur layer1 sebagai fitur input
    • atur uniqueid sebagai Unique Field ID
    • Tentukan jumlah grup (kami akan mengatakan 10)
    • Pilih x dan y untuk bidang analisis
    • Pilih "NO_SPATIAL_CONSTRAINT" untuk Batasan Spasial
    • Klik OK
  4. Menjalankan Alat Statistik Spasial> Mengukur Distribusi Geografis> Mean Center
    • Pilih Output dari # 3 sebagai Kelas Fitur Input
    • Pilih SS_Group sebagai Bidang Kasus
    • Klik OK
  5. Buka Analis Jaringan> Alat Alokasi Lokasi
    • Memuat output # 4 sebagai fasilitas
    • Memuat layer1 sebagai Poin Permintaan
    • Buka Atribut dan atur
      • Jenis Masalah sebagai Maksimalkan Cakupan Kapasitata
      • Fasilitas untuk Pilih sebagai 10 (dari # 3 di atas)
      • Kapasitas Default sebagai jumlah total fitur dalam layer1 dibagi dengan fasilitas untuk memilih dibulatkan (jadi jika 145 fitur dan 10 fasilitas / area, tetapkan sebagai 15)
      • Klik OK
        • Memecahkan
        • Poin permintaan Anda harus kurang lebih terdistribusi secara merata ke dalam 10 klaster geografis
LilHeb
sumber
Saya terjebak pada langkah lima metode Anda. Saya telah memeriksa ekstensi Network Analyst dan menambahkan toolbar Network Analyst. Tetapi sebagian besar berwarna abu-abu dan saya tidak melihat "Alat Alokasi Lokasi". Saya menggunakan 10.1.
Emil Brundage
0

Anda harus membuat Network Dataset terlebih dahulu menggunakan jalan-jalan Anda. Saya telah mencoba metode yang diusulkan ini dan sejauh ini lebih beruntung melakukan hal yang sama dengan Pengelompokan (langkah 3) dengan sendirinya, menggunakan koordinat X, Y dan k-means untuk bidang input (tidak sempurna, tetapi lebih cepat dan lebih dekat dengan apa yang saya lakukan) membutuhkan). Saya terbuka untuk komentar dan umpan balik orang lain.

Chris
sumber