Найшвидші методи зміни таблиць атрибутів з Python?


12

Нещодавно я написав швидку функцію Python для перетворення таблиці атрибутів у словник python, де ключ береться з визначеного користувачем унікального поля ідентифікатора (зазвичай це поле OID). Крім того, за замовчуванням всі поля копіюються у словник, але я включив параметр, що дозволяє вказати лише підмножину.

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

Це чудово підходить для відносно невеликих наборів даних, але я просто запустив його по таблиці, що містить близько 750 000 рядків і 15 полів - близько 100 Мб у базі даних геоданих. У цих випадках функція працює набагато повільніше, ніж я міг би очікувати: приблизно 5-6 хвилин (і це після копіювання таблиці в in_memoryробочу область). Мені дуже хотілося б знайти спосіб пришвидшити перетворення в словник, або отримати деяке розуміння щодо кращої стратегії маніпулювання великою кількістю даних атрибутів за допомогою Python.

UpdateCursors не спрацює добре для мене, оскільки коли змінюється один рядок, він може викликати зміни в кількох інших. Прокручування та обробка їх по одному занадто громіздко для того, що мені потрібно.


2
Обмежуючим фактором у тому, скільки ви можете оптимізувати ваш сценарій, може бути тривалість часу для перегляду курсору. Ви порівнювали час, необхідний для перегляду курсору, не будуючи словники?
Джейсон

2
@Jason, коментуючи рядки з subdict = {}наскрізь, del subdictдає час обробки приблизно 10 секунд.
nmpeterson

Ви, напевно, знаєте про це більше, ніж я, але єдине, що я запропонував би з точки зору оптимізації, - це те, чи subdict[field] = row[cursor_fields.index(field)]швидше викликати дзвінки, ніж телефонувати subdict[field] = row.getValue(field). В останньому сценарії ви б виконували один крок ... хоча різниця в продуктивності між індексуванням двох списків ( cursor_fieldsі row) та використанням одного ESRI-процесу може бути не набагато кращою, а може бути навіть гіршою!
Джейсон

Відповіді:


16

Я думаю, що проблема, ймовірно, у ваших двох рядках, де ви переходите над полями та додаєте кожне поле окремо до свого subdictсловника.

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

Ваш rowоб'єкт вже є кортежем у тому ж порядку, що і ваші поля, скористайтеся цим і використовуйте zipфункцію.

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

Це перемістилося через 218k запис 16-класового класу функцій геоданих баз даних за 8 секунд у моїй системі.

Правка: Спробував більш жорсткий тест. Записи 518k через віддалене з'єднання SDE з 16 полями, включаючи OBJECTID та Shape, працюють у 32-бітному. 11 секунд :)


1
Зауважте, що я зробив key_fieldперше поле, щоб я міг розраховувати на використання row[0]посилання на значення key_field. Я також повинен був змінити вашу змінну dictна attdict. dict - це ключове слово, і без цього ключового слова я не міг би скористатисяdict(zip())
blord-castillo

6
Розумний. Це саме той солодкий ідіоматичний Python, який arcpy.daмає на меті включити.
Jason Scheirer

Прекрасне розуміння. Любіть метод, і він справді допоміг.
nmpeterson
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.