Metode tercepat untuk memodifikasi tabel atribut dengan Python?


12

Beberapa waktu yang lalu, saya menulis fungsi Python cepat untuk mengonversi tabel atribut ke kamus python, di mana kuncinya diambil dari bidang ID unik khusus pengguna (biasanya bidang OID). Selain itu, secara default semua bidang disalin ke kamus, tetapi saya telah menyertakan parameter yang memungkinkan hanya subset ditentukan.

def make_attribute_dict(fc, key_field, attr_list=['*']):
    dict = {}
    fc_field_objects = arcpy.ListFields(fc)
    fc_fields = [field.name for field in fc_field_objects if field.type != 'Geometry']
    if attr_list == ['*']:
        valid_fields = fc_fields
    else:
        valid_fields = [field for field in attr_list if field in fc_fields]
    if key_field not in valid_fields:
        cursor_fields = valid_fields + [key_field]
    else:
        cursor_fields = valid_fields
    with arcpy.da.SearchCursor(fc, cursor_fields) as cursor:
        for row in cursor:
            key = row[cursor_fields.index(key_field)]
            subdict = {}
            for field in valid_fields:
                subdict[field] = row[cursor_fields.index(field)]
            dict[key] = subdict
            del subdict
    return dict

Ini berfungsi baik untuk dataset yang relatif kecil, tetapi saya hanya menjalankannya di atas meja yang berisi sekitar 750.000 baris dan 15 bidang - sekitar 100MB dalam file geodatabase. Pada ini, fungsi berjalan jauh lebih lambat daripada yang saya harapkan: sekitar 5-6 menit (dan ini setelah menyalin tabel ke in_memoryruang kerja). Saya benar-benar ingin menemukan cara untuk mempercepat konversi ke kamus, atau mendapatkan beberapa wawasan tentang strategi yang lebih baik untuk memanipulasi sejumlah besar data atribut menggunakan Python.

UpdateCursors tidak akan berfungsi dengan baik untuk saya, karena ketika satu baris berubah, ia berpotensi memicu perubahan di beberapa baris lainnya. Melewati dan memprosesnya satu per satu terlalu rumit untuk apa yang saya butuhkan.


2
Faktor pembatas dalam seberapa banyak Anda dapat mengoptimalkan skrip Anda mungkin adalah lamanya waktu yang diperlukan untuk beralih melalui kursor Anda. Sudahkah Anda membandingkan waktu yang diperlukan untuk beralih melalui kursor tanpa membangun kamus Anda?
Jason

2
@Jason mengomentari garis dari subdict = {}melalui del subdictmenghasilkan waktu pemrosesan sekitar 10 detik.
nmpeterson

Anda mungkin tahu lebih banyak tentang ini daripada saya, tetapi satu-satunya hal yang saya tawarkan dalam hal optimasi adalah melihat apakah panggilan subdict[field] = row[cursor_fields.index(field)]lebih cepat daripada menelepon subdict[field] = row.getValue(field). Dalam skenario terakhir Anda akan melakukan satu langkah ... meskipun perbedaan kinerja antara pengindeksan dua daftar ( cursor_fieldsdan row) dan menggunakan proses ESRI tunggal mungkin tidak jauh lebih baik dan bahkan mungkin lebih buruk!
Jason

Jawaban:


16

Saya pikir masalahnya adalah kemungkinan dua baris Anda di mana Anda pergi ke bidang dan menambahkan setiap bidang secara individual ke subdictkamus Anda .

for field in valid_fields:
    subdict[field] = row[cursor_fields.index(field)]

rowObjek Anda sudah menjadi tupel dalam urutan yang sama dengan bidang Anda, manfaatkan itu dan gunakan zipfungsinya.

def make_attribute_dict(fc, key_field, attr_list=['*']):
    attdict = {}
    fc_field_objects = arcpy.ListFields(fc)
    fc_fields = [field.name for field in fc_field_objects if field.type != 'Geometry']
    if attr_list == ['*']:
        valid_fields = fc_fields
    else:
        valid_fields = [field for field in attr_list if field in fc_fields]
    #Ensure that key_field is always the first field in the field list
    cursor_fields = [key_field] + list(set(valid_fields) - set([key_field]))
    with arcpy.da.SearchCursor(fc, cursor_fields) as cursor:
        for row in cursor:
            attdict[row[0]] = dict(zip(cursor.fields,row))
    return attdict

Ini tersendat melalui kelas fitur catatan 218k file 16k geodatabase fitur dalam 8 detik pada sistem saya.

Sunting: Mencoba tes yang lebih keras. Catatan 518k melalui koneksi SDE jarak jauh dengan 16 bidang termasuk OBJECTID dan Shape, dijalankan pada 32-bit. 11 detik :)


1
Perhatikan bahwa saya membuat key_fieldbidang pertama sehingga saya bisa mengandalkan penggunaan row[0]untuk referensi nilai key_field. Saya juga harus mengubah variabel Anda dictmenjadi attdict. dict adalah kata kunci, dan tanpa kata kunci itu saya tidak dapat menggunakandict(zip())
blord-castillo

6
Pintar. Ini adalah jenis Python idiomatik manis yang arcpy.dadimaksudkan untuk diaktifkan.
Jason Scheirer

Wawasan luar biasa. Suka metode ini, dan itu sangat membantu.
nmpeterson
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.