Menghitung atribut baru berdasarkan perubahan atribut lain menggunakan ArcGIS Desktop dengan Python?

11

Saya mencoba untuk mengklasifikasikan seperangkat data titik yang dikodekan waktu menjadi perilaku berdasarkan atribut yang berbeda.

Saya telah membuat atribut yang 0 untuk rumah dan 1 untuk jauh berdasarkan lokasi, dan sekarang ingin menghitung perjalanan jauh dari rumah (satu set poin 01111111111110akan menjadi satu perjalanan karena dimulai dan berakhir di rumah). Saya telah menambahkan bidang atribut yang akan memiliki nomor perjalanan, tetapi tidak tahu cara menghitung bidang sehingga didasarkan pada bidang home / away.

Berikut adalah contoh data GPS (menggunakan "*" untuk menunjukkan informasi yang tidak relevan dan hanya mengindeks waktu 1, 2, dll.), Indikator "Home / Away" yang dijelaskan di atas, dan indikator perjalanan yang diinginkan, "Perjalanan", yang perlu saya hitung:

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
....

Kumpulan data saya terlalu besar untuk dilalui secara manual dan nomor setiap perjalanan dalam tabel atribut, jadi apakah ada cara untuk menghitung bidang berdasarkan pada bagaimana atribut home / away dipesan dan setiap "rumpun" dari poin jauh ditetapkan sebagai perjalanan?

Ini adalah tulang telanjang dari apa yang tampak seperti kode Python (Saya tidak berpengalaman dengan kode).

Ekspresi:

trip = Reclass(!home!)

Codeblock:

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  

Setelah menggunakan skrip yang direkomendasikan matt wilkie saya telah membuat beberapa perubahan sehingga perjalanan pertama saya adalah nomor 1, yang kedua adalah 2, dll.

Berikut adalah kode yang dimodifikasi dari 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

Kemudian saya tinggal pilih home = 0 dan hitung field perjalanan saya kembali ke 0. Perjalanan yang tertata rapi.

AlmaTom
sumber

Jawaban:

12

Untuk ini, Anda dapat menggunakan UpdateCursor , yang membuka kelas fitur atau tabel dan melangkah melalui setiap catatan (baris) secara bertahap.

Skrip di bawah ini berfungsi pada data pengujian ini

+-----------------------+
| 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

Akhir blok perjalanan sebenarnya dijalankan untuk awal perjalanan juga, tetapi karena penghitung perjalanan benar kalk ganda pada baris awal-perjalanan-baris tidak masalah. Batalkan komentar cetak di blok itu untuk melihat apa yang saya maksud.

Python secara otomatis menambahkan implisit rows.next()di akhir untuk for row in rowsblok.

Ini mengasumsikan integritas data. Ini akan berantakan jika ada jumlah ganjil nol catatan Home / Away berturut-turut ( 000atau 00000). Perjalanan yang hanya terdiri dari mulai dan berhenti harus baik-baik saja, misalnya urutan 3 perjalanan 01..10 00 01..10, di mana ruang menunjukkan kesenjangan antara perjalanan. Dengan kata lain, validasikan hasilnya!

matt wilkie
sumber
2
+1, Anda HARUS melakukan ini dalam kursor pembaruan. Alat CalculateField tidak menjamin bahwa blok kode akan dijalankan hanya sekali, sehingga tripvariabel dapat diinisialisasi ulang setiap kali sewenang-wenang.
Jason Scheirer
Ini bekerja sangat baik karena semua perjalanan saya diberikan satu angka untuk semua poin dalam perjalanan, namun semua poin di rumah diberi nomor baru (yaitu data saya mulai dengan poin di rumah sekarang bernomor 1, 2, 3, .. ... 136 dan kemudian perjalanan pertama saya diberi label 137). Itu bukan masalah besar karena saya bisa mengembalikan semua poin "rumah" ke 0, tetapi akan lebih baik jika perjalanan saya dimulai pada 1 dan nomor yang merata setelah itu. Ada saran?
AlmaThom
@ Alice, saya tidak menguji, tetapi yang harus Anda lakukan hanyalah mengomentari atau menghapus row.TRIP = tripbaris di masing-masing dari dua blok yang menangani awal dan akhir perjalanan. (dan, kalau dipikir-pikir itu, rows.updateRow(row)yang mengikuti, karena tidak ada yang menyelamatkan di sana lagi.)
matt wilkie
Menyelesaikan kesalahan! skrip saya sekarang memiliki tiga bagian:
AlmaThom
5

Bantuan ArcGIS 10 dalam "menghitung contoh bidang" menunjukkan kepada Anda cara "Menghitung nilai akumulatif dari bidang numerik." Ini akan melakukan trik, asalkan data secara fisik dalam urutan temporal yang dimaksud.

Untuk menerapkannya secara langsung, balikkan indikator [Home / Away] Anda (kurangi dari 1) sehingga "0" berarti "jauh" dan "1" berarti "rumah". Saya menyebutnya [Jauh / Rumah] dalam contoh di bawah ini.

Hitung nilai kumulatifnya - [Kumulatif] dalam contoh.

Tambahkan satu dan bagi dua - [Perjalanan] dalam contoh (hampir).

Terakhir, atur [Trip] ke nol untuk semua catatan "rumah". Sekarang hasilnya setuju dengan contoh:

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
....

Sebagai catatan, inilah kode yang diambil dari bantuan ArcGIS 10. Saya memodifikasinya sedikit sehingga akan melakukan setiap langkah sekaligus: sekarang Anda hanya perlu menjalankannya. Seharusnya jelas di mana [Home / Away] terbalik dan di mana langkah "tambah 1, bagi 2" terjadi.

Ekspresi:

acc(!Home/Away!)

Jenis Ekspresi:

PYTHON_9.3

Blok Kode:

t=0
def acc(i):
  global t
  if t:
    t += (1-i)
  else:
    t = 1
  if i:
    return (t+1)/2
  else:
    return 0
whuber
sumber
3
Untuk sejumlah besar catatan ini tidak akan berfungsi. Codeblock kembali berjalan setiap beberapa ratus ribu baris (bersama dengan siklus pengumpulan sampah penuh) sehingga takan diatur ulang ke 0 di tempat-tempat yang tampaknya acak.
Jason Scheirer
2
Terima kasih, @Jason: Saya tidak mengetahui bug itu. Itu adalah show-stopper nyata. <B>> Saya pikir ArcGIS seharusnya ditingkatkan sehingga lebih baik untuk masalah mainan yang lebih kecil? </rant>
whuber
1
Bukan bug, itu sebenarnya detail implementasi yang diwarisi dari implementasi VBScript untuk mencoba meminimalkan kebocoran memori (pengguna menambahkan ke daftar untuk setiap catatan tetapi tidak pernah benar-benar menggunakan daftar untuk apa pun, misalnya). Saya cukup yakin saya menyingkirkan penyegaran di 11 karena itu adalah perilaku yang tidak jelas, tapi saya tidak ingat.
Jason Scheirer
1
@Jason Itu eufemisme baru bagi saya: "detail implementasi." Eufemisme lain adalah "fitur" dan "perilaku tidak berdokumen." Mawar dengan nama lain ...
Whuber
2
Begini cara saya melihatnya, @Jason: halaman bantuan itu sendiri memberikan kode yang saya sajikan. Oleh karena itu, ada pernyataan implisit di bagian ESRI bahwa kode itu berfungsi. Menurut Anda, itu tidak; memang, di bawah karakterisasi Anda itu bisa gagal secara signifikan, diam-diam, tanpa peringatan, dan tak terduga. Itu bukan hanya bug, itu bentuk bug paling buruk yang mungkin. "Atur ulang berkala" bukan "perbaikan," itu adalah kluge yang hanya membuat IMHO situasi lebih buruk.
whuber