Daha çox

Bənzər qaçışlarla üst-üstə düşən və ya yaxın sətirləri müəyyənləşdirmək və silmək?

Bənzər qaçışlarla üst-üstə düşən və ya yaxın sətirləri müəyyənləşdirmək və silmək?


Səth sularının axışını göstərən xətləri olan şəkillərim var. Bu formalı sənədləri bir şərtlə təmizləməyim və sadələşdirməyim lazımdır ki, bəzi sətirlər digərinə yaxın və oxşar işləsə, bu sətirlər silinməlidir.

Python 2.7, ArcMap 10.2 və Windows 7 istifadə edirəm.

İki həll yolunu sınadım:

Həll 1: ESRI arcpy modulundan istifadə edərək xətləri təkrarlayın, düzəldinbuferhər bir xətt üzərində 10 metr məsafədə ayrı-ayrılıqda istifadə edinYerə görə seçiniləTamamilə ehtiva edirşərt (bufer edildiyi orijinal sətir olmadan) vəsilinbu sətirlər. Sonra növbəti sətri təkrarlayın. Bu yaxşı işləyir, amma Yerə görə seçin çox yavaş idi və təmizlənməsi lazım olan 244 formalı sənəd olduğum üçün birlikdə 48 milyon xətt var, buna görə təxminən. Forma düzəltmək üçün 200 000 sətir və bunu sürətli etmək üçün ssenariyə ehtiyacım var.

Həll 2: Əvvəlki həlldəki kimi, xətlər boyunca təkrarlama istifadə edirəm və ayrıca istifadə edirəmbufer, lakin sonra Yerə görə seçin istifadə etməkdən çəkinmək istəyirəm, ona görə də istifadə edirəmKliptamponlu xətlər və sonrauzunluqları müqayisə etkəsilməmiş xətlərin və kəsilmiş xətlərin. Uzunluqlar eyni idisə - deməli, bu sətirlərin tamamilə buferə aid olduğu mənasını verir - bu sətirlərin ID-lərini siyahıya alıb orijinal shapefile silmək üçün toplayıram (kəsilmişdən yox, yalnız temp idi). Ancaq bu həll yolunda Clip funksiyası o qədər lənətə gəldi ki, lənətə gəldi yavaş, buna görə də mənim üçün əlverişli deyil.

İndi arcpy modulu istifadə edərək ayrılmaq istəyirəm, çünki bu qədər böyük bir məlumatda istifadə üçün uyğun deyil. Əvvəlki həllərdən birinin prosedurunu yenidən qurmaq üçün GDAL / OGR istifadə etmək istəyirəm, amma həqiqətən OGR alqoritmlərini itirirəm. İndiyə qədər səsləndirdiyim tək şey şəkilləndirmə və xətlərin arasından təkrarlamaqdır, amma buferi necə düzəldəcəyimi, yaxınlıqdakı bənzər xətləri müəyyən edib silməyi düşünmürəm.

Tək sətirdə təkrarlanan şəkillər:

Və son nəticəni göstərən şəkillər:


Düşünürəm ki, yaşadığınız sürət problemi hər xüsusiyyətin ətrafında döngə və döngənin içərisində geoprosessinq alətlərindən istifadə etməkdir. Onlar bunun üçün nəzərdə tutulmayıb. Bütün məlumat dəstini bir anda emal etməyi gözləyirlər. Buna görə döngünün qarşısını almaq üçün skriptinizi yenidən qurun və "bir fincan qəhvə içmə vaxtında" tamamlanmalıdır. Məlumatlar mənim fikrimcə o qədər azdır ki, daha çox vaxt çəkməməlidir.

Birinci addım: Forma sənədlərini unutun! Bunlar o qədər köhnə məktəbdirlər ki, heç bir yerdə o qədər sürətli deyillər, daha yaxşı bir məkan indeksinə sahib deyillər və sadəcə köhnəlmişlər. Tək bir fayl məlumat bazasından istifadə edin.

Verilənlər bazasının lokal sürətli diskdə, tercihen SSD-də olduğundan əmin olun.

yaddaşın tükənməməsi üçün prosesi əsnasında məlumatları bölüşdürə bilərsən, amma arcpy-də həndəsə obyektlərindən istifadə etmənin bütün məkan operatorlarına sahib olduğunu və son dərəcə sürətli olduğunu anlayıram.

Təmizləmə vektorlarından daha yaxşı yanaşmalar ola bilər. Şübhəsiz ki, onlar bir növ raster səthindən yaradıldı? Mənbəyə baxıb xətləri yenidən bərpa edə bilməzsiniz?

Nümunə vektor dəsti yaratmaq üçün asan bir yol düşünə bilmirəm. Demo yazmaq üçün bir yerə göndərə bilərsinizmi?

Budur iki sətirdə 1000 sətirdə işləyən bir demo skript:

# ------------------------------------------------- ------------------------------ # Adı: çökmə_hattı3.py # Məqsəd: yaxınlıqdakı axın xətlərinin dağılması prosesi # # Müəllif: kimo # # Yaradıldı: 14.02.2016 # Müəllif hüquqları: (c) kimo 2016 # Lisenziya: Creative Commons 3.0 Yeni Zelandiya # ------------------------ -------------------------------------------------- ----- # Metod: # Tədqiqat sahəsindəki xətləri prioritet baxımından uzunluğa görə sıralayın # Bərabər xüsusiyyət sayılan bir bölmə həndəsəsi yaradın # Hər bölmə üçün xüsusiyyətləri seçin # Yaxın_Bölmə OD cədvəli yaradın # Yaxın cədvələ əlavə edin # Hər yaxın OD üçün qeyd: # setdə hələ yoxsa: # seti yığmaq üçün FID əlavə et # və seti silmək üçün # # orijinal id-lərin SQL sorğu qatını yaradın və idxal arcpy import sys import os idxal datetime import logging # global variables start = datetime.datetime.now () ws = 'd: /project/stackExchange/sample.gdb' arcpy.env.workspace = ws arcpy.env.overwriteOutput = True in_fc = "kontur" fc = in_fc + '_sort' buf_distan ce = 250 # veriye uyğun max_near_count = 5 keep_fc = in_fc + '_keep' rem_fc = in_fc + '_remove' near_tab = 'near' logging.basicConfig (filename = os.path.dirname (ws) + "/ contour.log" , # format = "% (asctime) s% (message) s", datefmt = "% m /% d /% Y% I:% M:% S% p", filemode = "w", level = logging. DEBUG) logging.debug (vars ()) def create_near (qat): "" "hər bölmə üçün yaxın cədvəl yaradın və yığın" "" arcpy.GenerateNearTable_analysis (in_features = qat, near_features = layer, out_table = "in_memory /" + qat + '_ tab', search_radius = buf_distance, location = "NO_LOCATION", angle = "NO_ANGLE", closest = "ALL", closest_count = max_near_count, method = "PLANAR") arcpy.management.Append ("in_memory /" + layer + '_tab', near_tab) count = int (arcpy.management.GetCount ("in_memory /" + layer + '_ tab'). getOutput (0)) return count def split_near_tab (near_tab, fc): # Toplamaq üçün Yaxın cədvəlin üstündə təkrarlayın ana və ətraf xətt ID-ləri, # [daha qısa xətlər əldə etmək üçün yaxın xətt həndəsəsindəki bir tampondan istifadə edərək daha yaxşı bir şəkildə düzəldilə bilər. ciddi metod, lakin bu, namizədləri məhdudlaşdırır] keep_set = set () remove_set = set () last_id = arcpy.da.SearchCursor ilə yox (yaxın_tab, ['IN_FID', 'NEAR_FID', 'NEAR_DIST', 'NEAR_RANK']) kimi cur: cərgədəki sıra üçün: # ən uzun FID-i saxlayın və əlaqəli bütün sətirləri silin fid = sıra [0] nearid = sıra [1] əgər silmək yoxsa silmək: saxlamaq_set.add (fid) # dəstə yalnız bir dəfə əlavə edərsə, yaxın deyilsə keep_set-də: remove_set.add (nearid) # yazdığımızı saymaq "keep {} kaldır {} total {}". format (len (keep_set), len (remove_set), len (keep_set) + len (remove_set)) # İndi sadəcə seçim dəsti hazırlayın və # düyməni ixrac etmək lazımdır, ancaq OBJECTID onsuz da keep_SQL = "" "OBJECTID in {}" "". format (str (tuple (keep_set))) "{}… {}" yazdır. format (keep_SQL [0:20], keep_SQL [-20:]) arcpy.management.MakeFeatureLayer (fc, "keep_lay", keep_SQL) arcpy.management.CopyFeatures ("keep_lay", keep_fc) # qeyd üçün silindi Remove_SQL = " "" OBJECTID in {} "" ". Format (str (tuple (remove_set))) print" {}… {} ". Format (remove_SQL [0:20], remove_SQL [-20:]) arcpy.mana gement.MakeFeatureLayer (fc, "remove_lay", remove_SQL) arcpy.management.CopyFeatures ("remove_lay", rem_fc) return # -------------- main --------- ---------------- arcpy olmadığı təqdirdə OID tərəfindən prioritet olaraq # xüsusiyyət sinfi obyektlərini uzunluğu üzrə sıralayın. Var (fc): arcpy.management.Sort (in_fc, fc, [['Shape_Length') , 'İLƏN']]) "mənbə sayı {}" yazdırın. Format (arcpy.management.GetCount (fc)) # daha sürətli yaxınlıq işlənməsi üçün temp surətini 3 nöqtəyə qədər ümumiləşdirin # Bütün axtarış məsafələrini hissə-hissə işləyin (əziz köhnə Esri edir nöqtələr xaricindəki xüsusiyyət sinifləri ilə problemi olan GenerateNear üçün bölmə # istifadə etməyin) # tolerantlıq həddi ilə hər bitişik xüsusiyyətə məsafələrin bir OD matrisi yaradın, # və cədvəlin ölçüsündə partlamamasını təmin etmək üçün ən yaxın maksimum say # kafel sayı üçün vacibdir performans, ballar üçün 100K, polylines üçün 10K arcpy.CreateCartographicPartitions_cartography (in_features = fc, out_features = "partition", feature_count = "10000") g = arcpy.Geometry () total_near = 0 fayans = arcpy.manage ment.CopyFeatures ("partition", g) msg ​​= "Fayanslar {}". format (len (plitələr)) logging.debug (msg) print msg # əlavə etmək üçün boş bir fayl yaradın, beləliklə ilk plitənin arcpy.Exists olduqda dəqiq vaxtı var (near_tab): arcpy.management.Delete (near_tab) arcpy.management.CopyRows ('near_template', near_tab) # həndəsə siyahısındakı əsas döngə, plitələrdəki kafel üçün imlec deyil: arcpy.management.MakeFeatureLayer (fc, 'fc_lay ') arcpy.management.SelectLayerByLocation (' fc_lay ',' INTERSECT ', fayans) feature_count = int (arcpy.management.GetCount (' fc_lay '). getOutput (0)) əgər xüsusiyyət_ sayı> 0: start_tile = datetime.datetime.now () n = create_near ('fc_lay') total_near + = n # tənzimləmə və darboğazlıqları müəyyənləşdirmək üçün vacib olan vaxt jurnalı = datetime.datetime.now () - start_tile rate = elapsed.seconds / (n / 1000000.0) msg ​​= "fayans {: 3} say {: 5} yaxın {: 5} keçən {} nisbət {: 8.1f} saniyə başına M ".format (plitələr .index (kirəmit), xüsusiyyət_sayısı, n, keçən, dərəcə) logging.debug (msg) çap msg else: msg = "skip {: 3}". format (tile.index (tile)) print msg logging.deb ug (msg) msg ​​= "total_near {}". format (total_near) print msg logging.debug (msg) # artık prosesi masa yaxınlığında bir addımda birləşdirin split_near_tab (near_tab, fc) # ---------- --------------------- msg = "Yaxşı Bitti {}". format (datetime.datetime.now () - start) logging.debug (msg) print msg logging.shutdown ()

İndi bütün bir ölkə üçün 1: 50K kontur istifadə edərək 1: 250K konturla uyğunlaşdırmaq üçün incəltməyə çalışaraq məlumatları genişləndirdim. Bu, ilk istifadə etdiyim çaylardan daha çox axın xətlərinə bir qədər yaxındır. GenerateNearTable daha böyük bir dəstdə uğursuz olur, buna görə Kartoqrafik Bölmələrdən istifadə etməliyəm. Lakin SelectByLocation bölmə vasitəsi də uğursuz oldu! Təəccüblü deyil ki, Toolbox-da heç bir şey yaxşı tərəzi vermir.

Beləliklə, növbəti addım bölməni daha sürətli bir şeylə əvəz etməkdir ... Bununla birlikdə bir giriş modulu və bir müddət qoyaraq GenerateNear-ı söndürmək bölmənin yavaş bir hissə olmadığını göstərir. Polylines-i orta nöqtələrlə əvəz etsəm, bütün proses 100.000 xüsusiyyətli böyük arakəsmələrlə milyon qeyddə ortalama 58 saniyə boyunca uçur, lakin polylines ilə 5000 qeyd bölmələri ilə 28.000 saniyəyə qədər yavaşlayır. Yaxşı niyə yalnız orta nöqtələrdən istifadə etməyək? Yaxşı, bu bir qədər də sadələşdirilib, amma tutaq ki, çox xətlər uclara və orta nöqtəyə qədər ümumiləşdirilib (yalnız seçim üçün)? Bu seçimi sürətləndirə bilər və son sətirlər hələ mənbədən seçilir. Test ssenarisini arakəsmələr daxil olan ən son təkrarla əvəz etdim.

Kontur nümunələrim çox uzun sinlu polinellərdir, amma axın xətlərinin demək olar ki, düz, lakin gözəl əyri olduğunu görürəm. Bəlkə də analiz üçün çox çox zirvələri var. Onlar ağır şəkildə ümumiləşdirilmiş olsaydı, daha sürətli işləyə bilər. Orijinal sətir sonunda ID ilə əvəz edilə bilər. Konturları maksimum 500 verticiyə endirdimsə, sürəti 10 dəfə artırdı və daha da ümumiləşdirilə bilsəydim, başqa bir 10 faktorunu təxmin edirəm.

Python 64 bit istifadə etməyə çalışdım və vaxtı 50% azaltdı, amma 1000% yaxşılaşmağı axtarıram.


İkinci həll yolunuzun birincisindən daha yavaş olduğuna inanıramKlipdaxili varYerə görə seçimüstəgəl digər həndəsi əməliyyatlar. Buna görə ilk alqoritminizdə bəzi inkişaflar təklif edirəm:

  1. @ Artwork21 şərhinə görə, mümkünsə formalı sənədləri birləşdirin. məs. eyni sxemi paylaşırlar. Bu prosedur, formalı sənədlərin üzərindəki əlavə bir dövriyyəni aradan qaldırır və bu səbəbdən geoprosessinq funksiyaları çağırışlarını azaldır.
  2. Döngüdə buferləşdirmək əvəzinə, bütün shapefile-i döngənin xaricində bufer edin və sonra buferləşdirilmiş shapefile xüsusiyyətlərinin üstündə döngü yaradın.
  3. Tamponlama zamanı istifadə etdiyinizə əmin olunyaddaşdamüvəqqəti bufer nəticələrini diskə yazmağın qarşısını almaq üçün açar söz / çıxış bahadır.

Düşünmək lazım olan bəzi şeylər.

  1. Nümunəniz hər hansı bir göstəricidirsə, işinizi bitirdikdən sonra 5 milyondan çox qeydə sahib olacaqsınız. Nə formalı sənədlər, nə də şəxsi geodatabazalar bunu yaxşı idarə edə bilməzlər, buna görə ya bir fayl geodatabase və ya SDE istifadə etməlisiniz.

  2. 48 milyon qeydin işlənməsi, xüsusən də məkan seçimi ilə əlaqəli olduqda, sürətli olmayacaq. Bəlkə də bunun əvəzinə bir gecədə və arxa planda işləyə bilən sabit bir skript qurmağı düşünün, buna görə heç bir şəkildə mane olmayacaqsınız. Onu necə kəsməyinizdən asılı olmayaraq, bu, kompüterinizi çox sayda sıxılmış siqnal etməyə məcbur edəcəkdir.

  3. 48 milyon qeyddə seçim etmək çox qaynaqlı olardı. Ən azından bu çox yavaş olacaq. Bütün formaları birləşdirmək istəmirsiniz.

  4. 1000 qeyddə bir skript testini 48 milyon qeyd ilə müqayisə edə bilməzsiniz. Kompüter nə qədər çox mənbədən istifadə etməlidirsə, o qədər yavaş olacaq.

  5. İn_memory boşluğundan istifadə edirsinizsə, nə qədər yaddaş istifadə etdiyinizi düşünün. Yaddaşdakı böyük məlumat dəstləri ilə işləyəcəksinizsə, təkrarlamaları izləməlisiniz, diskə yazmalı və yaddaşı vaxtaşırı təmizləməlisiniz.

  6. Əlbətdə, təbəqələrinizin məkan indekslərinə sahib olduğundan əmin olun.

Həqiqi cavabımı alarkən, doğru yolda olduğunuzu düşünürəm.

Xətləri eyni vaxtda sildiyiniz zaman necə dolaşırsınız? Bəzi yavaşlığınıza səbəb ola bilər.

Budur nə təklif edim.

  1. Orijinal shapefiles saxlamalısınız, buna görə işləyən bir nüsxə yaratmaq üçün onları bir fayl geodatabase-ə çevirin.
  2. Filtrlənmiş xətləriniz üçün bir çıxış xüsusiyyət sinfi yaradın.
  3. Forma şəkillərinə baxın (indi xüsusiyyət sinifləridir) ...
  4. Record_count üçün bir dəyişən təyin edin (və shapefile qeydlərinin sayını əldə edin - indi xüsusiyyət sinifləri - yalnız nitq rəqəmi).
  5. Record_count> 0 üçün bir müddət döngəsinə başlayın
  6. "Shapefile" dəki ilk sətri tutun və bufer edin.
  7. Yerinizə görə seçiminizi edin.
  8. İlk seçilmiş qeydləri tutun və çıxış xüsusiyyət sinifinə əlavə edin (seçilmiş dəstdə bir imleci istifadə edin).
  9. Seçilmiş bütün qeydləri silin.
  10. Bir qeyd sayını əldə edin və record_count dəyişəninizi yenidən qurun
  11. While loopunuzun altındakı əlinizdən gələni təmizlədiyinizə əmin olun (və while loopunuzu sona çatdırın).
  12. Və "shapefile" loopunuzun altındakı hər şeyi təmizlədiyinizə əmin olun (və shapefile loopunuzu bitirin).

Orijinal shapefiles məkan baxımından ayrı deyildisə, skripti çıxış xüsusiyyət sinifində təkrarlamağınız lazımdır.

Bu mükəmməl olmaya bilər, çünki ssenarini əslində yazmamışam, amma inşallah işə başlayacaqsınız.