Вычисление нового атрибута на основе изменений в другом атрибуте с использованием ArcGIS Desktop с Python?


11

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

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

Ниже приведен пример данных GPS (с использованием «*» для обозначения нерелевантной информации и простого индексации времени как 1, 2 и т. Д.), Индикатора «Home / Away», описанного выше, и индикатора требуемой поездки «Поездка», который мне нужно вычислить:

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  

После использования рекомендованного сценария Мэтта Уилки я внес некоторые изменения, так что моя первая поездка - номер 1, моя вторая - 2, и т. Д. И т. Д.

Вот код, модифицированный из Matt's:

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

Задний конец блока отключения фактически запускается и для начала отключения, но, поскольку счетчик отключений правильный, двойной расчет в строке начала-отключения не имеет значения. Раскомментируйте оператор print в этом блоке, чтобы понять, что я имею в виду.

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

Это предполагает целостность данных. Это испортится, если в строке ( 000или 00000) будет нечетное количество нулевых записей Home / Away . Поездка, которая состоит только из запуска и остановки, должна быть в порядке, например, последовательность из трех поездок 01..10 00 01..10, где пробелы обозначают промежутки между поездками. Другими словами, подтвердите результаты!


2
+1, вы ДОЛЖНЫ сделать это в курсоре обновления. Инструмент CalculateField не гарантирует, что блок кода будет запущен только один раз, поэтому tripпеременная может быть повторно инициализирована любое произвольное количество раз.
— Джейсон Шейрер,

Это прекрасно работает, поскольку всем моим поездкам присваивается один номер для всех точек в поездке, однако всем точкам дома присваивается новый номер (т.е. мои данные начинаются с точек дома, которые теперь имеют номера 1, 2, 3, .. ... 136 и тогда моя первая поездка помечена 137). Это не имеет большого значения, потому что я могу вернуть все «домашние» баллы на 0, но было бы неплохо, если бы мои поездки начинались с 1 и после этого были равномерным числом. Любой совет?
— AlmaThom

@ Алиса, я не проверял, но все, что тебе нужно сделать, это закомментировать или удалить row.TRIP = tripстроку в каждом из двух блоков, которые обрабатывают начало и конец поездки. (и, если подумать, то, rows.updateRow(row)что следует, так как больше там нечего спасать.)
— Matt Wilkie

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

5

Справка ArcGIS 10 в разделе «Рассчитать примеры полей» показывает, как «Рассчитать накопительное значение числового поля». Это поможет, если данные физически находятся в заданном временном порядке.

Чтобы применить его напрямую, инвертируйте индикатор [Home / Away] (вычтите его из 1), чтобы «0» означало «отсутствующий», а «1» означало «домашний». Я называю это [Away / Home] в примере ниже.

Вычислите его совокупную стоимость - [Накопительная] в примере.

Добавьте один и разделите на два - [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
@ Джейсон Для меня это новый эвфемизм: «детали реализации». Другими эвфемизмами являются «особенность» и «недокументированное поведение». Роза под любым другим именем ...
— whuber

2
Вот как я это вижу, @Jason: сама страница справки содержит код, который я представил. Поэтому со стороны ESRI существует неявное утверждение о том, что код работает. По вашему мнению, это не так; действительно, по вашей характеристике он может потерпеть неудачу значительно, тихо, без предупреждения и непредсказуемо. Это не просто ошибка, это самая отвратительная из возможных ошибок. «Периодический сброс» - это не «исправление», это «клюж», который только ухудшает ситуацию ИМХО.
— whuber
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.