Saya punya tabel dengan 8 kolom dan ~ 16,7 juta catatan. Saya perlu menjalankan satu set persamaan if-else pada kolom. Saya telah menulis skrip menggunakan modul UpdateCursor, tetapi setelah beberapa juta catatan kehabisan memori. Saya bertanya-tanya apakah ada cara yang lebih baik untuk memproses 16,7 juta catatan ini.
import arcpy
arcpy.TableToTable_conversion("combine_2013", "D:/mosaic.gdb", "combo_table")
c_table = "D:/mosaic.gdb/combo_table"
fields = ['dev_agg', 'herb_agg','forest_agg','wat_agg', 'cate_2']
start_time = time.time()
print "Script Started"
with arcpy.da.UpdateCursor(c_table, fields) as cursor:
for row in cursor:
# row's 0,1,2,3,4 = dev, herb, forest, water, category
#classficiation water = 1; herb = 2; dev = 3; forest = 4
if (row[3] >= 0 and row[3] > row[2]):
row[4] = 1
elif (row[2] >= 0 and row[2] > row[3]):
row[4] = 4
elif (row[1] > 180):
row[4] = 2
elif (row[0] > 1):
row[4] = 3
cursor.updateRow(row)
end_time = time.time() - start_time
print "Script Complete - " + str(end_time) + " seconds"
PEMBARUAN # 1
Saya menjalankan skrip yang sama di komputer dengan 40 gb RAM (komputer asli hanya memiliki 12 gb RAM). Ini berhasil diselesaikan setelah ~ 16 jam. Saya merasa bahwa 16 jam terlalu lama, tetapi saya tidak pernah bekerja dengan set data yang besar sehingga saya tidak tahu apa yang diharapkan. Satu-satunya tambahan baru untuk skrip ini adalah arcpy.env.parallelProcessingFactor = "100%"
. Saya mencoba dua metode yang disarankan (1) melakukan 1 juta catatan dalam batch dan (2) menggunakan SearchCursor dan menulis output ke csv. Saya akan segera melaporkan perkembangannya.
PEMBARUAN # 2
Pembaruan SearchCursor dan CSV bekerja dengan sangat baik! Saya tidak memiliki waktu menjalankan yang tepat, saya akan memperbarui pos ketika saya berada di kantor besok tapi saya akan mengatakan perkiraan waktu berjalan ~ 5-6 menit yang cukup mengesankan. Saya tidak mengharapkannya. Saya membagikan kode saya yang tidak dipoles, semua komentar dan perbaikan disambut:
import arcpy, csv, time
from arcpy import env
arcpy.env.parallelProcessingFactor = "100%"
arcpy.TableToTable_conversion("D:/mosaic.gdb/combine_2013", "D:/mosaic.gdb", "combo_table")
arcpy.AddField_management("D:/mosaic.gdb/combo_table","category","SHORT")
# Table
c_table = "D:/mosaic.gdb/combo_table"
fields = ['wat_agg', 'dev_agg', 'herb_agg','forest_agg','category', 'OBJECTID']
# CSV
c_csv = open("D:/combine.csv", "w")
c_writer = csv.writer(c_csv, delimiter= ';',lineterminator='\n')
c_writer.writerow (['OID', 'CATEGORY'])
c_reader = csv.reader(c_csv)
start_time = time.time()
with arcpy.da.SearchCursor(c_table, fields) as cursor:
for row in cursor:
#skip file headers
if c_reader.line_num == 1:
continue
# row's 0,1,2,3,4,5 = water, dev, herb, forest, category, oid
#classficiation water = 1; dev = 2; herb = 3; ; forest = 4
if (row[0] >= 0 and row[0] > row[3]):
c_writer.writerow([row[5], 1])
elif (row[1] > 1):
c_writer.writerow([row[5], 2])
elif (row[2] > 180):
c_writer.writerow([row[5], 3])
elif (row[3] >= 0 and row[3] > row[0]):
c_writer.writerow([row[5], 4])
c_csv.close()
end_time = time.time() - start_time
print str(end_time) + " - Seconds"
UPDATE # 3 Pembaruan akhir. Total waktu menjalankan skrip adalah ~ 199,6 detik / 3,2 menit.
sumber
Jawaban:
Anda dapat menulis Objectid dan hasil perhitungan (cate_2) ke file csv. Kemudian gabungkan csv ke file asli Anda, isi bidang, untuk mempertahankan hasilnya. Dengan cara ini Anda tidak memperbarui tabel menggunakan kursor DA. Anda dapat menggunakan kursor Pencarian.
sumber
Maaf, jika saya terus menghidupkan kembali utas lama ini. Idenya adalah untuk melakukan pernyataan if-else pada raster gabungan dan kemudian menggunakan bidang baru di pencarian untuk membuat raster baru. Saya mempersulit masalah dengan mengekspor data sebagai tabel dan memperkenalkan alur kerja yang tidak efisien yang ditangani oleh @Alex Tereshenkov. Setelah menyadari yang jelas, saya mengumpulkan data menjadi 17 pertanyaan (masing-masing 1 juta) seperti yang disarankan oleh @FelixIP. Butuh rata-rata setiap batch ~ 1,5 menit untuk menyelesaikan dan total waktu run ~ 23,3 menit. Metode ini menghilangkan kebutuhan untuk bergabung dan saya pikir metode ini paling baik menyelesaikan tugas. Berikut ini skrip yang direvisi untuk referensi di masa mendatang:
sumber
Lookup
dan mengekspor raster dengan kategori yang baru ditentukan.arcpy.env.parallelProcessingFactor = "100%"
tidak berpengaruh pada skrip Anda. Saya tidak melihat alat apa pun di sana yang memanfaatkan lingkungan itu.Anda dapat mencoba mengubah menggunakan CalculateField_management . Ini menghindari perulangan menggunakan kursor dan, dengan melihat opsi Anda untuk nilai kategori, Anda bisa mengatur ini sebagai empat subproses yang muncul secara berurutan. Ketika setiap subproses selesai, memorinya dilepaskan sebelum memulai yang berikutnya. Anda menerima hit kecil (milidetik) untuk menelurkan setiap subproses.
Atau, jika Anda ingin mempertahankan pendekatan Anda saat ini, miliki subproses yang mengambil x-rows sekaligus. Memiliki proses utama untuk mengendarainya dan, seperti sebelumnya, Anda terus mencari memori Anda setiap kali selesai. Bonus melakukannya dengan cara ini (terutama melalui proses python yang berdiri sendiri) adalah bahwa Anda dapat menggunakan lebih banyak dari semua core Anda sebagai sub-sub proses pemuliaan dalam multthreading python yang Anda dapatkan di sekitar GIL. Ini dimungkinkan dengan ArcPy dan pendekatan yang saya gunakan di masa lalu untuk melakukan churn data besar-besaran. Jelas menjaga potongan data Anda turun kalau tidak Anda akan kehabisan memori lebih cepat!
sumber
Logika manipulasi data dapat ditulis sebagai pernyataan SQL UPDATE menggunakan ekspresi KASUS, yang dapat Anda jalankan menggunakan GDAL / OGR, misalnya melalui OSGeo4W dengan
gdal-filegdb
diinstal.Inilah alur kerjanya, yang menggunakan
osgeo.ogr
alih-aliharcpy
:Di meja yang sama dengan lebih dari 1 juta catatan, kueri ini memakan waktu 18 menit. Jadi mungkin masih butuh ~ 4 hingga 5 jam untuk memproses 16 juta rekaman.
sumber
arcpy
tetapi saya menghargai jawabannya. Saya perlahan mencoba menggunakan GDAL lebih banyak.Pembaruan kode di bagian # 2 dalam pertanyaan Anda tidak menunjukkan bagaimana Anda bergabung dengan
.csv
file kembali ke tabel asli di geodatabase file Anda. Anda mengatakan bahwa skrip Anda membutuhkan waktu ~ 5 menit untuk dijalankan. Ini terdengar adil jika Anda hanya mengekspor.csv
file tanpa melakukan penggabungan. Ketika Anda akan mencoba untuk membawa.csv
file kembali ke ArcGIS, Anda akan menemukan masalah kinerja.1) Anda tidak dapat melakukan penggabungan langsung dari
.csv
ke tabel geodatabase, karena.csv
file tersebut tidak memiliki OID (memiliki bidang yang dihitung dengan nilai unik tidak akan membantu karena Anda masih perlu mengonversi.csv
file Anda ke tabel geodatabase). Jadi, beberapa menit untukTable To Table
alat GP (Anda bisa menggunakanin_memory
ruang kerja untuk membuat tabel temp di sana, akan sedikit lebih cepat).2) Setelah Anda memuatnya
.csv
ke dalam tabel geodatabase, Anda ingin membuat indeks pada bidang yang akan Anda ikuti (dalam kasus Anda, sumberobjectid
vaue dari.csv
file. Ini akan memakan waktu beberapa menit pada tabel baris 16mln.3) Maka Anda perlu menggunakan alat
Add Join
atauJoin Field
GP. Tidak ada yang akan bekerja dengan baik di meja besar Anda.4) Setelah itu, Anda perlu melakukan
Calculate Field
alat GP untuk menghitung bidang yang baru bergabung. Banyak menit di sini; bahkan lebih lagi, perhitungan bidang membutuhkan lebih banyak waktu ketika bidang yang berpartisipasi dalam perhitungan berasal dari tabel gabungan.Singkatnya, Anda tidak akan mendapatkan apa pun yang mendekati 5 menit yang Anda sebutkan. Jika Anda akan berhasil dalam satu jam, saya akan terkesan.
Untuk menghindari berurusan dengan pemrosesan dataset besar dalam ArcGIS, saya sarankan mengambil data Anda di luar ArcGIS ke dalam
pandas
kerangka data dan melakukan semua perhitungan Anda di sana. Ketika Anda selesai, cukup tulis baris data frame kembali ke tabel geodatabase baruda.InsertCursor
(atau Anda bisa memotong tabel yang sudah ada dan menulis baris Anda ke sumbernya).Kode lengkap yang saya tulis untuk benchmark ini adalah di bawah ini:
Di bawah ini adalah output dari IO Debug (jumlah yang dilaporkan adalah jumlah baris dalam tabel yang digunakan) dengan info waktu eksekusi untuk fungsi individual:
Memasukkan baris dengan
da.InsertCursor
membutuhkan waktu yang konstan, yaitu, jika memasukkan 1 baris, katakanlah, 0,1 detik, untuk memasukkan 100 baris akan memakan waktu 10 detik. Sayangnya, 95% + dari total waktu eksekusi dihabiskan untuk membaca tabel geodatabase dan kemudian memasukkan baris kembali ke geodatabase.Hal yang sama berlaku untuk membuat
pandas
bingkai data darida.SearchCursor
generator dan untuk menghitung bidang. Karena jumlah baris dalam tabel geodatabase sumber Anda berlipat ganda, demikian juga waktu eksekusi skrip di atas. Tentu saja, Anda masih perlu menggunakan Python 64bit karena selama eksekusi, beberapa struktur data yang lebih besar akan ditangani dalam memori.sumber
Lookup
untuk membuat raster berdasarkan nilai-nilai di kolom baru. Metode saya memiliki banyak langkah yang tidak perlu dan alur kerja yang tidak efisien, saya seharusnya menyebutkan ini dalam pertanyaan awal saya. Hidup dan belajar. Saya akan mencoba skrip Anda akhir minggu ini.