Phương pháp nhanh nhất để sửa đổi bảng thuộc tính với Python?


12

Cách đây một thời gian, tôi đã viết một hàm Python nhanh để chuyển đổi bảng thuộc tính thành từ điển python, trong đó khóa được lấy từ trường ID duy nhất do người dùng chỉ định (thường là trường OID). Ngoài ra, theo mặc định, tất cả các trường được sao chép vào từ điển, nhưng tôi đã bao gồm một tham số cho phép chỉ một tập hợp con được chỉ định.

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

Điều này hoạt động rất tốt cho các bộ dữ liệu tương đối nhỏ, nhưng tôi chỉ chạy nó trên một bảng chứa khoảng 750.000 hàng và 15 trường - khoảng 100 MB trong một cơ sở dữ liệu địa lý tệp. Về những điều này, chức năng chạy chậm hơn nhiều so với tôi dự kiến: khoảng 5-6 phút (và đây là sau khi sao chép bảng vào in_memorykhông gian làm việc). Tôi thực sự muốn tìm cách tăng tốc độ chuyển đổi sang từ điển hoặc hiểu rõ hơn về một chiến lược tốt hơn để thao túng một lượng lớn dữ liệu thuộc tính bằng Python.

UpdateCursors sẽ không hoạt động tốt đối với tôi, bởi vì khi một hàng thay đổi, nó có khả năng kích hoạt các thay đổi ở một số người khác. Xoay vòng và xử lý chúng cùng một lúc là quá cồng kềnh cho những gì tôi cần.


2
Yếu tố giới hạn trong số lượng bạn có thể tối ưu hóa tập lệnh của mình có thể là khoảng thời gian cần thiết để lặp qua con trỏ. Bạn đã so sánh thời gian cần thiết để lặp qua con trỏ mà không xây dựng từ điển của bạn chưa?
Jason

2
@Jason nhận xét các dòng từ subdict = {}thông qua del subdictmang lại thời gian xử lý khoảng 10 giây.
nmpeterson 18/03/13

Bạn có thể biết nhiều về điều này hơn tôi, nhưng điều duy nhất tôi sẽ cung cấp về mặt tối ưu hóa là xem liệu cuộc gọi subdict[field] = row[cursor_fields.index(field)]có nhanh hơn gọi điện hay không subdict[field] = row.getValue(field). Trong kịch bản sau, bạn sẽ thực hiện một bước ... mặc dù sự khác biệt về hiệu suất giữa lập chỉ mục hai danh sách ( cursor_fieldsrow) và sử dụng một quy trình ESRI duy nhất có thể không tốt hơn nhiều và thậm chí còn tồi tệ hơn!
Jason

Câu trả lời:


16

Tôi nghĩ vấn đề có thể là hai dòng của bạn, nơi bạn sẽ đi qua các trường và nối thêm từng trường vào subdicttừ điển của bạn .

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

rowĐối tượng của bạn đã là một tuple theo thứ tự giống như các trường của bạn, hãy tận dụng lợi thế đó và sử dụng ziphàm.

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

Điều này đã vượt qua một lớp tính năng cơ sở dữ liệu địa lý tệp hồ sơ 218k hồ sơ 218k trong 8 giây trên hệ thống của tôi.

Chỉnh sửa: Đã thử một bài kiểm tra nghiêm ngặt hơn. 518k bản ghi qua kết nối SDE từ xa với 16 trường bao gồm OBRIID và Shape, chạy ở 32 bit. 11 giây :)


1
Lưu ý rằng tôi đã tạo key_fieldtrường đầu tiên để tôi có thể dựa vào việc sử dụng row[0]để tham chiếu giá trị của key_field. Tôi cũng đã phải thay đổi biến của bạn dictthành attdict. dict là một từ khóa, và không có từ khóa đó, tôi không thể sử dụngdict(zip())
blord-castillo 18/03/13

6
Tài giỏi. Đây chính xác là loại Python thành ngữ ngọt ngào arcpy.dacó nghĩa là để kích hoạt.
Jason Scheirer 18/03/13

Cái nhìn sâu sắc Yêu phương pháp, và nó thực sự có ích.
nmpeterson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.