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は、私にとってはうまくいきません。なぜなら、1つの行が変更されると、他のいくつかの行で変更を引き起こす可能性があるからです。一度に1つずつループして処理するのは、私が必要とするものでは面倒です。


2
スクリプトを最適化できる範囲を制限する要因は、カーソルを反復処理するのにかかる時間の長さです。辞書を作成せずにカーソルを繰り返し処理するのにかかる時間を比較しましたか?
ジェイソン

2
@Jasonからsubdict = {}through までの行をコメントアウトするdel subdictと、処理時間は約10秒になります。
-nmpeterson

おそらく私よりもこれについて知っているでしょうが、最適化に関して私が提供する他の唯一のことは、呼び出しsubdict[field] = row[cursor_fields.index(field)]がcallより速いかどうかを調べることですsubdict[field] = row.getValue(field)。後者のシナリオでは、1つのステップを実行します。ただし、2つのリスト(cursor_fieldsおよびrow)のインデックス作成と単一のESRIプロセスの使用のパフォーマンスの差はそれほど良くないかもしれませんし、さらに悪くなるかもしれません!
ジェイソン

回答:


16

問題はおそらく、フィールドを越えて各フィールドをsubdict辞書に個別に追加する2行であると思います。

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は、32ビットで実行されるOBJECTIDとShapeを含む16のフィールドを持つリモートSDE接続で記録します。11秒:)


1
の値を参照するのkey_fieldに使用できるように、最初のフィールドを作成したことに注意してください。また、変数をに変更する必要がありました。dictはキーワードであり、そのキーワードなしでは使用できませんでしたrow[0]key_fielddictattdictdict(zip())
blord-castillo

6
賢い。これはまさに、arcpy.da有効にすることを意図した、甘い慣用的なPythonの一種です。
ジェイソンシャイラー

素晴らしい洞察。メソッドが大好きで、本当に役立ちました。
nmpeterson
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.