Обчислити новий атрибут на основі змін іншого атрибута за допомогою ArcGIS Desktop з Python?


11

Я намагаюся класифікувати набір даних, що кодують час від gps, на поведінку на основі різних атрибутів.

Я створив атрибут, який дорівнює 0 для дому та 1 для відсутнього, залежно від місця розташування, і тепер хочу пронумерувати поїздки далеко від дому (набір балів 01111111111110буде однією поїздкою, оскільки вона почалася і закінчилася вдома). Я додав поле атрибутів, яке матиме номери поїздки, але не знаю, як обчислити поле, тож воно базується на полі дома / вдома.

Ось приклад даних 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 і т.д. і т.д.

Ось код, змінений з матових:

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

Тоді я просто вибираю для дому = 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

Кінцевий кінець блоку подорожі насправді запускається також для початку подорожі, але оскільки лічильник подорожі правильний, подвійний виклик у рядку початку поїздки не має значення. Відкиньте вислів друку в цьому блоці, щоб побачити, що я маю на увазі.

Python автоматично додає неявну rows.next()в кінці для for row in rowsблоку.

Це передбачає цілісність даних. Він зіпсується, якщо в рядку ( 000або 00000) буде колись непарна кількість нульових записів "Домашні / гості" . Поїздка, яка складається лише з старту та зупинки, повинна бути нормальною, наприклад, 3 послідовністю поїздки 01..10 00 01..10, де пробіли позначають прогалини між поїздками. Іншими словами, підтверджуйте результати!


2
+1, Ви ОБОВ'ЯЗКОВО це зробити в курсорі оновлення. Інструмент CalculateField не гарантує, що блок коду буде запущений лише один раз, тому tripзмінна може бути повторно ініціалізована будь-яку довільну кількість разів.
Jason Scheirer

Це чудово справляється з тим, що всім моїм поїздкам присвоюється одне число для всіх пунктів подорожі, проте всім балам вдома присвоєно нове число (тобто мої дані починаються з балів удома, які тепер мають номер 1, 2, 3, ... 136, і тоді моя перша поїздка - це позначка 137). Це не велика справа, тому що я можу повернути всі "домашні" бали до 0, але було б добре, якби мої поїздки починалися з 1 і були рівномірними після цього. Будь-яка порада?
AlmaThom

@Alice, я не тестував, але все, що вам потрібно зробити, - це прокоментувати або видалити row.TRIP = tripрядок у кожному з двох блоків, які обробляють початок і кінець подорожі. (і, подумайте про це, rows.updateRow(row)що випливає, тому що там більше нічого не врятувати.)
matt wilkie

Розібрався з глюком! тепер мій сценарій складається з трьох частин:
AlmaThom

5

Довідка ArcGIS 10 у розділі "Приклади обчислення поля" показує вам, як "Обчислити накопичувальне значення числового поля". Це дозволить зробити хитрість, якщо дані фізично перебувають у визначеному часовому порядку.

Щоб застосувати його безпосередньо, переверніть індикатор [Дома / вдалині] (відніміть його від 1) так, що "0" означає "геть", а "1" означає "дім". Я називаю це [У гостях / вдома] у наведеному нижче прикладі.

Обчисліть його кумулятивне значення - [Сукупне] у прикладі.

Додайте одне і розділіть на два - [Подорож] у прикладі (майже).

Нарешті, встановіть [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. Я трохи змінив її, щоб вона зробила кожен крок відразу: тепер вам потрібно лише запустити її. Повинно бути зрозуміло, куди перевертається [Дім / Відвідувач] і де відбувається крок "додати 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 у, здавалося б, випадкових місцях.
Jason Scheirer

2
Дякую, @Jason: Я не знав про цю помилку. Це справжнє шоу-пробка. <rant> Я думав, що ArcGIS повинен був збільшити масштаб так, що це добре для більш ніж маленьких проблем з іграшками? </rant>
whuber

1
Це не помилка, це фактично деталі реалізації, успадковані від реалізації VBScript, щоб спробувати звести до мінімуму витоки пам'яті (користувачі, що додають до списку для кожної записи, але ніколи фактично не використовують цей список ні для чого, наприклад). Я майже впевнений, що я позбувся оновлення в 11, тому що це неочевидна поведінка, але я не пам’ятаю.
Jason Scheirer

1
@Jason Це новий для мене евфемізм: "деталізація реалізації". Іншими евфемізмами є "особливість" та "недокументована поведінка". Роза за будь-яким іншим ім’ям ...
whuber

2
Ось як я це бачу, @Jason: сама довідка містить код, який я представив. Тому існує неявне твердження з боку ESRI про те, що код працює. За вами, це не так; Дійсно, за вашою характеристикою він може вийти з ладу суттєво, безшумно, без попередження та непередбачувано. Це не просто помилка, це найгустіша форма помилки. "Періодичне скидання" - це не "виправлення", це клубок, який тільки погіршує ситуацію ІМХО.
whuber
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.