使用带有Python的ArcGIS Desktop,基于另一个属性的更改来计算新属性?


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

我的数据集太大,无法手动进行遍历并在属性表中对每次行程进行编号,因此,有什么方法可以根据归位/离开属性的排序方式来计算字段,并且将每个“聚集”离去点都指定为旅行?

这些是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号,依此类推。

这是从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。

Answers:


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

行程块的尾端实际上也可以在行程开始时运行,但是由于行程计数器是正确的,因此在开始行程行上的double calc无关紧要。在该块中取消注释打印语句,以查看我的意思。

Python自动rows.next()在该for row in rows块的末尾添加一个隐式。

这假设数据完整性。如果一行(00000000)中的零个Home / Away记录的奇数个,它将弄乱。仅由开始和停止组成的行程应该是可以的,例如3个行程序列01..10 00 01..10,其中空格表示行程之间的间隔。换句话说,验证结果!


2
+1,您必须在更新游标中执行此操作。CalculateField工具不能保证该代码块仅运行一次,因此trip可以任意多次将变量重新初始化。
杰森·谢里尔

这样做非常有效,因为我为所有旅行分配了一个数字,但是我给所有在家的点都赋予了一个新的数字(即,我的数据从现在在家的点开始编号为1、2、3,.. ... 136,然后我的第一次旅行都标记为137)。没什么大不了的,因为我可以将所有“家”点都还原为0,但是如果我的旅程从1开始并且之后是平均数,那就太好了。有什么建议吗?
AlmaThom 2012年

@Alice,我没有测试,但是您需要做的就是注释掉或删除row.TRIP = trip处理行程起点和终点的两个方框中的每一行。(然后考虑一下,rows.updateRow(row)
接下来

整理故障!我的脚本现在分为三个部分:
AlmaThom 2012年

5

ArcGIS 10帮助“计算字段示例”下的内容向您展示了如何“计算数字字段的累加值”。 这将这样的伎俩, 所提供的数据在物理上预期的时间顺序。

要直接应用它,请将您的[Home / Away]指示器反转(减去1),以使“ 0”表示“离开”,“ 1”表示“回家”。在下面的示例中,我称此为[Away / Home]。

计算其累计值-在示例中为[Cumulative]。

在示例中(几乎)加一并除以2 [旅行]。

最后,将所有“ home”记录的[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对我来说是一个新的委婉说法:“实现细节”。其他委婉说法是“功能”和“未记录的行为”。一朵别称玫瑰的花……
呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜还将对照把住将会着手了

2
@Jason,这是我的看法:帮助页面本身提供了我提供的代码。因此,在ESRI方面隐含断言该代码有效。根据您的说法,并非如此;实际上,根据您的描述,它可能会严重地,无声地,无预警地无法预测失败这不仅是一个错误,而且是可能的最讨厌的错误形式。“定期重置”不是“解决方案”,而是一种只会使情况恶化的恕我直言。
ub
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.