用Python修改属性表的最快方法?


12

不久前,我编写了一个快速的Python函数,用于将属性表转换为python字典,其中的键来自用户指定的唯一ID字段(通常是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个字段的表上运行了它-在文件地理数据库中大约有100MB。在这些函数上,该函数的运行速度比我预期的要慢得多:大约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_fieldsrow)与使用单个ESRI流程之间的性能差异可能不会好很多,甚至可能更糟!
杰森

Answers:


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

在我的系统上,这在8秒钟内就解决了一个218k记录16个字段文件地理数据库要素类的问题。

编辑:尝试了更严格的测试。518k通过远程SDE连接记录,其中包含16位字段(包括OBJECTID和Shape),以32位运行。11秒:)


1
请注意,我创建key_field了第一个字段,以便可以依靠row[0]引用的值key_field。我还必须将您的变量更改dictattdict。dict是一个关键字,没有该关键字,我将无法使用dict(zip())
blord-castillo 2013年

6
聪明。这正是arcpy.da要启用的甜美惯用的Python 。
詹森·谢里尔

真知灼见。喜欢这种方法,确实很有帮助。
nmpeterson
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.