PythonとArcGIS Desktopを使用して、別の属性の変更に基づいて新しい属性を計算しますか?


11

一連のgps時間エンコードポイントデータを、異なる属性に基づいて動作に分類しようとしています。

自宅に0、自宅に1の属性を作成しましたが、自宅からの旅行に番号を付けたいと思います(自宅01111111111110で開始および終了するため、ポイントのセットは1つの旅行になります)。旅行番号を持つ属性フィールドを追加しましたが、フィールドの計算方法がわからないため、ホーム/アウェイフィールドに基づいています。

GPSデータの(「*」を使用して無関係な情報を示し、時間を1、2などとして単純にインデックス付けします)、上記の「ホーム/アウェイ」インジケータ、および希望のトリップインジケータ「トリップ」、計算する必要があります:

Time Lat Lon Home/Away Trip
   1   *   *         0    0
   2   *   *         1    1
   3   *   *         1    1
....
  12   *   *         1    1
  13   *   *         0    0
  14   *   *         0    0
  15   *   *         1    2
  16   *   *         1    2
.... 
  34   *   *         1    2
  35   *   *         0    0
  36   *   *         0    0
  37   *   *         1    3
....

私のデータセットは大きすぎて手動で移動して属性テーブルの各旅行に番号を付けることができないので、home / away属性の順序付け方法に基づいてフィールドを計算する方法はありますか?トリップ?

これらは、Pythonコードがどのように見えるかという基本的なものです(私はコードの経験がありません)。

式:

trip = Reclass(!home!)

コードブロック:

def Reclass(home):  
  if (home = 0):  
    return 0   
  elif (home = 1 and lastValue = 0):  
    return _(incremental numbering?)_  
  elif (home = 1 and lastValue = 1):  
    return lastValue  

matt wilkieの推奨スクリプトを使用した後、最初の旅行が1番、2番目が2番などになるようにいくつかの変更を加えました。

以下は、mattから変更されたコードです。

import arcpy
rows = arcpy.UpdateCursor("test2")

trip = 0
for row in rows:
    if row.home == 0:
        prev = row.home
        row.TRIP = trip
        rows.updateRow(row)

    elif row.home == 1 and prev == 0:
        trip += 1
        prev = row.home
        row.TRIP = trip
        rows.updateRow(row)
        rows.next()

    elif row.home == 1 and prev == 1:
        prev = row.home
        row.TRIP = trip
        rows.updateRow(row)
        rows.next()

    row.TRIP = trip
    rows.updateRow(row)


del row, rows

次に、home = 0を選択して、旅行フィールドを0に戻します。きちんと順序付けられた旅行。

回答:


12

このために、フィーチャクラスまたはテーブルを開き、各レコード(行)を段階的にステップ実行するUpdateCursorを使用できます。

以下のスクリプトは、このテストデータで動作します

+-----------------------+
| Time| Home_Away|Trip  |
+-----|----------|------+
|  1  |  0       | <nul>|
|  2  |  1       | <nul>|
|  4  |  1       | <nul>|
|  5  |  0       | <nul>|
|  6  |  0       | <nul>|
|  7  |  1       | <nul>|
|  9  |  1       | <nul>|
| 12  |  1       | <nul>|
| 13  |  0       | <nul>|
+-----------------------+

import arcpy
fc = r'D:\s\py\pyscratch.gdb\gps_points'

# open the feature class and create the cursor
rows = arcpy.UpdateCursor(fc)

trip = 0
for row in rows:
    if row.HOME_AWAY == 0:
        trip += 1           # start of new trip, increment counter
        row.TRIP = trip     # calc the TRIP field to be current trip#
        rows.updateRow(row) # save
        print "Trip %s started at %s" % (trip, row.TIME)

    # keep cycling through records until HOME_AWAY is not 1
    while row.HOME_AWAY == 1:
        row.TRIP = trip
        rows.updateRow(row)
        rows.next() # move to next record

    # this is for the trailing end of a trip, the second 0
    # print "     %s ended at %s" % (trip, row.TIME)
    row.TRIP = trip
    rows.updateRow(row)

# remove programming objects and data locks
# the data itself is left alone
del row, rows

トリップブロックの末尾は実際にはトリップの開始時にも実行されますが、トリップカウンターが正しいため、begin-trip-rowの二重計算は関係ありません。そのブロックのprintステートメントのコメントを解除して、意味を確認してください。

Python rows.next()は、for row in rowsブロックの末尾に暗黙的に自動的に追加します。

これは、データの整合性を前提としています。行内に奇数のホーム/アウェイレコードが1 000つでもあると、混乱します(または00000)。開始と停止のみで構成される旅行は、大丈夫である必要があります。たとえば、3つの旅行シーケンスの01..10 00 01..10場合、スペースは旅行間のギャップを示します。つまり、結果を検証します!


2
+1、更新カーソルでこれを行わなければなりません。CalculateFieldツールは、コードブロックが1回だけ実行されることを保証しないため、trip変数は任意の回数再初期化できます。
ジェイソンシャイラー

これは、旅行中のすべてのポイントにすべての旅行に1つの番号が割り当てられるという点で優れていますが、自宅のすべてのポイントに新しい番号が付けられます(つまり、私のデータは自宅のポイント1、2、3、.. ... 136そして、私の最初の旅行はすべて137)とラベル付けされています。すべての「ホーム」ポイントを0に戻すことができるので、大したことではありませんが、旅行が1から始まり、その後は偶数であるとよいでしょう。何かアドバイス?
アルマトム

@アリス、私はテストしませんでしたが、あなたがする必要があるのはrow.TRIP = trip、旅行の開始と終了を処理する2つのブロックのそれぞれの行をコメントアウトまたは削除することだけです。(そして、それについて考えるようになりましたrows.updateRow(row)。もうそこに保存するものはないので。)
マットウィルキー

グリッチを整理しました!私のスクリプトは現在3つの部分に分かれています。
AlmaThom

5

「フィールドの計算例」の下のArcGIS 10ヘルプは、「数値フィールドの累積値を計算する」方法を示しています。 データが物理的に意図した時間的順序にある​​場合、これはトリックを行います

直接適用するには、[Home / Away]インジケーターを反転(1から減算)し、「0」が「離れている」を意味し、「1」が「ホーム」を意味するようにします。以下の例では、これを[Away / Home]と呼びます。

その累積値を計算します。例では[Cumulative]です。

1つを追加し、2で除算します。例では[Trip](ほぼ)です。

最後に、すべての「ホーム」レコードに対して[Trip]をゼロに設定します。 これで、結果は例と一致します。

Time Lat Lon Home/Away Trip Away/Home Cumulative 
   1   *   *         0    0         1          1
   2   *   *         1    1         0          1
   3   *   *         1    1         0          1
.... 
  12   *   *         1    1         0          1
  13   *   *         0    0         1          2
  14   *   *         0    0         1          3
  15   *   *         1    2         0          3
  16   *   *         1    2         0          3
.... 
  34   *   *         1    2         0          3
  35   *   *         0    0         1          4
  36   *   *         0    0         1          5
  37   *   *         1    3         0          5
....

記録のために、ArcGIS 10ヘルプから取得したコードを以下に示します。 少しずつ変更して、すべてのステップを一度に実行できるようにしました。これで、実行するだけで済みます。[Home / Away]が反転し、「1を加算、2で除算」ステップが発生する場所を明確にする必要があります。

式:

acc(!Home/Away!)

式のタイプ:

PYTHON_9.3

コードブロック:

t=0
def acc(i):
  global t
  if t:
    t += (1-i)
  else:
    t = 1
  if i:
    return (t+1)/2
  else:
    return 0

3
多数のレコードの場合、これは機能しません。コードブロックは、数十万行ごとに(完全なガベージコレクションサイクルとともに)再実行されるためt、一見ランダムな場所で0にリセットされます。
ジェイソンシャイラー

2
ありがとう、@ Jason:そのバグを知りませんでした。それは本当のショーストッパーです。<rant> ArcGISは小さなおもちゃの問題よりも良いようにスケールアップされるはずだと思いましたか?</ rant>
whuber

1
バグではありません。実際には、メモリリーク(ユーザーがすべてのレコードのリストに追加しますが、実際には何にも使用しないなど)を最小限に抑えるためにVBScript実装から継承された実装の詳細です。11の更新は明らかな動作ではないため、削除したと確信していますが、覚えていません。
ジェイソンシャイラー

1
@Jasonそれは私にとって新しいe曲表現です:「実装の詳細」。他のe曲表現は「機能」と「文書化されていない動作」です。Aは...他の名前でバラ
whuber

2
@Jasonの見方は次のとおりです。ヘルプページ自体が、提示したコードを提供します。したがって、ESRIの一部には、コードが機能するという暗黙の主張がありますあなたによると、そうではありません。確かに、あなたの特性評価では、警告なしに予測できないほどに大きく、静かに失敗することがありますそれは単なるバグではなく、最も厄介なバグです。「定期的なリセット」は「修正」ではなく、状況を悪化させるだけの手掛かりです。
whuber
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.