用ArcPy将多边形划分为* n *个相等计数的组?


10

我的工作任务之一是将包裹分成几组。这些小组将由代理商用来与业主交谈。目的是通过将彼此靠近的宗地分组在一起,以及将宗地划分为相等的数量,以便使工作平均分配,来简化代理的工作。特工的数量可以从一对波动到10+。

目前,我会手动执行此任务,但如果可能的话,希望自动执行该过程。我探索了各种ArcGIS工具,但似乎没有一个适合我的需求。我尝试了一个使用near_analysis和选择多边形的脚本(在python中),但它是随机的,要永久完成一个半正确的结果,比起从头开始手动完成所有工作要花费更长的时间进行修复。

有没有可靠的方法可以自动执行此任务?

结果示例(希望没有出现黄色的除法):

分割包裹



您是否尝试过分组分析(空​​间统计)?
FelixIP

我也贴我使用的实际程序的伪代码,看看它是否可能帮助gis.stackexchange.com/questions/123289/...
FelixIP

@crmackey我很感谢我答案的链接,但是我不确定如何调整链接的代码(分割多边形)以适应此问题(对多边形进行分组)。
韧皮部

Answers:


4

原始集:

在此处输入图片说明

创建它的伪副本(在TOC中拖动CNTRL),并使用克隆使空间连接一对多。在这种情况下,我使用距离500m。输出表:

在此处输入图片说明

  1. 从此表中删除PAR_ID = PAR_ID_1的记录-很容易。

  2. 遍历表并删除记录,其中上面的任何记录的(PAR_ID,PAR_ID_1)=(PAR_ID_1,PAR_ID)。不太容易,请使用acrpy。

计算流域质心(UniqID = PAR_ID)。它们是节点或网络。使用空间连接表通过线连接它们。这是必定涵盖在该论坛某个位置的单独主题。

在此处输入图片说明

下面的脚本假定节点表如下所示: 在此处输入图片说明

MUID来自地块,P2013是总结的领域。在这种情况下,= 1仅用于计数。[rcvnode]-脚本输出,用于在定义的组/集群中存储等于第一个节点的组ID NODEREC。

链接表结构并突出显示重要字段

在此处输入图片说明

时间存储链接/边缘权重,即从节点到节点的旅行成本。在这种情况下,等于1,因此到所有邻居的旅行费用是相同的。[fi]和[ti]是连接的节点的顺序数。要填充此表,请在此论坛上搜索如何分配要链接的节点和如何分配要链接的节点。

为我自己的工作台mxd定制的脚本。必须修改,并使用字段和源的命名进行硬编码:

import arcpy, traceback, os, sys,time
import itertools as itt
scriptsPath=os.path.dirname(os.path.realpath(__file__))
os.chdir(scriptsPath)
import COMMON
sys.path.append(r'C:\Users\felix_pertziger\AppData\Roaming\Python\Python27\site-packages')
import networkx as nx
RATIO = int(arcpy.GetParameterAsText(0))

try:
    def showPyMessage():
        arcpy.AddMessage(str(time.ctime()) + " - " + message)
mxd = arcpy.mapping.MapDocument("CURRENT")
theT=COMMON.getTable(mxd)

查找节点层

theNodesLayer = COMMON.getInfoFromTable(theT,1)
theNodesLayer = COMMON.isLayerExist(mxd,theNodesLayer)

获取链接层

    theLinksLayer = COMMON.getInfoFromTable(theT,9)
    theLinksLayer = COMMON.isLayerExist(mxd,theLinksLayer)
    arcpy.SelectLayerByAttribute_management(theLinksLayer, "CLEAR_SELECTION")        
    linksFromI=COMMON.getInfoFromTable(theT,14)
    linksToI=COMMON.getInfoFromTable(theT,13)
    G=nx.Graph()
    arcpy.AddMessage("Adding links to graph")
    with arcpy.da.SearchCursor(theLinksLayer, (linksFromI,linksToI,"Times")) as cursor:
            for row in cursor:
                (f,t,c)=row
                G.add_edge(f,t,weight=c)
            del row, cursor
    pops=[]
    pops=arcpy.da.TableToNumPyArray(theNodesLayer,("P2013"))
    length0=nx.all_pairs_shortest_path_length(G)
    nNodes=len(pops)
    aBmNodes=[]
    aBig=xrange(nNodes)
    host=[-1]*nNodes
    while True:
            RATIO+=-1
            if RATIO==0:
                    break
            aBig = filter(lambda x: x not in aBmNodes, aBig)
            p=itt.combinations(aBig, 2)
            pMin=1000000
            small=[]
            for a in p:
                    S0,S1=0,0
                    for i in aBig:
                            p=pops[i][0]
                            p0=length0[a[0]][i]
                            p1=length0[a[1]][i]
                            if p0<p1:
                                    S0+=p
                            else:
                                    S1+=p
                    if S0!=0 and S1!=0:
                            sMin=min(S0,S1)                        
                            sMax=max(S0,S1)
                            df=abs(float(sMax)/sMin-RATIO)
                            if df<pMin:
                                    pMin=df
                                    aBest=a[:]
                                    arcpy.AddMessage('%s %i %i' %(aBest,sMax,sMin))
                            if df<0.005:
                                    break
            lSmall,lBig,S0,S1=[],[],0,0
            arcpy.AddMessage ('Ratio %i' %RATIO)
            for i in aBig:
                    p0=length0[aBest[0]][i]
                    p1=length0[aBest[1]][i]
                    if p0<p1:
                            lSmall.append(i)
                            S0+=p0
                    else:
                            lBig.append(i)
                            S1+=p1
            if S0<S1:
                    aBmNodes=lSmall[:]
                    for i in aBmNodes:
                            host[i]=aBest[0]
                    for i in lBig:
                            host[i]=aBest[1]
            else:
                    aBmNodes=lBig[:]
                    for i in aBmNodes:
                            host[i]=aBest[1]
                    for i in lSmall:
                            host[i]=aBest[0]

    with arcpy.da.UpdateCursor(theNodesLayer, "rcvnode") as cursor:
            i=0
            for row in cursor:
                    row[0]=host[i]
                    cursor.updateRow(row)
                    i+=1

            del row, cursor
except:
    message = "\n*** PYTHON ERRORS *** "; showPyMessage()
    message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
    message = "Python Error Info: " +  str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()

6组输出示例:

在此处输入图片说明

您将需要网站软件包NETWORKX http://networkx.github.io/documentation/development/install.html

脚本将所需的簇数作为参数(上例中为6)。它使用节点和链接表来制作具有相等权重/距离的行进边缘(时间= 1)的图形。它考虑所有节点的组合为2,并计算两组邻居的[P2013]总数。当达到所需比率时,例如第一次迭代时达到(6-1)/ 1,则继续降低比率目标,即4,依此类推,直到1。起点非常重要,因此请确保您的“末端”节点位于顶部您的节点表(排序?)请参见示例输出中的前3组。它有助于避免在每次下一次迭代时进行“分支切割”。

脚本自定义可从mxd运行:

  1. 您不需要导入COMMON。是我自己的事情,它读取我自己的环境表,其中指定了NodesLayer,theLinksLayer,linksFromI,linksToI。用您自己的节点和链接层命名替换相关行。
  2. 请注意,字段P2013可以存储任何内容,例如租户数或宗地面积。如果是这样,您可能会聚簇多边形以容纳大约相等数量的人等。

实际上,节点和链接层只是视觉上的东西。空间连接的清理表可以轻松替换链接表,因为已经分配了往返节点。多边形表可以轻松地用作节点表,只需添加ReceivingNode字段并将序列号从该字段传送回“链接” [FromI]和[ToI]。
FelixIP

看起来不错 非常感谢您的回答。您能解释更多的原因,而不仅仅是原因吗?您的代码上的注释将是巨大的。
Emil Brundage 2015年

请按照我之前对您的问题的评论中的超链接。如果这是“为什么”的意思,我试图解释这种方法。我撤消了有关启动节点重要性的评论,因为在发布对您的Q的答案后,我随机更改了记录顺序以尝试杀死脚本。什么也没发生,仍然产生了合理的结果。
FelixIP 2015年

要清理空间连接表,只需删除PAR_ID = PAR_ID_1,因为NETWORKX的无向图中的边/链接[0,2]等于edge [2,0]。我可以发布更新的脚本,不确定是否会影响我的声誉
FelixIP

@EmilBrundage一看,它可能会帮助为什么问题gis.stackexchange.com/questions/165057/...
FelixIP

2

您应该使用“组分析”工具来实现您的目标。该工具是@phloem指出的“空间统计”工具箱中的出色工具。但是,您应该微调该工具以适应您的数据和问题。我创建了一个类似的场景,就像您发布的场景一样,得到的响应接近您的目标。

提示:使用ArcGIS 10.2,当我运行该工具时,它抱怨缺少python软件包“六个”。因此,请确保先安装链接

脚步:

  1. 向您的多边形类添加字段以保留唯一值
  2. 添加另一个名称为Short的字段,例如“ SameGroup”
  3. 您可以使用字段计算器为所有行的该字段分配1。只需将一行更改为2。 新增栏位

  4. 设置“组分析”工具参数,如下所示: 组分析

尝试更改“邻居数”参数以适合您的需要。

结果快照:

样例输入多边形

小组分析的结果


2
我之前曾研究过Group Analysis。它处理的是空间,但据我所知不能算在内。我从阅读文档,查看您的示例以及执行自己的测试中获得的所有经验都不允许按相等数量的多边形进行分组。
埃米尔·布伦达奇

为什么您需要平等(代理人偏离路线)?但是,如果我们添加该约束,那么为什么要基于空间关系对数据进行聚类(分组)!
Farid Cheraghi 2015年

1
因为老板这么说。另外,请尽量减少旅行时间。
Emil Brundage 2015年

1

基本上,您需要一个大小相等的聚类方法,因此您可以在网上使用此关键字进行搜索。对我来说,在stats.SE中有一个很好的答案,答案之一是使用Python实现。如果您熟悉arcpy,则应该可以将其与数据一起使用。

首先,需要计算多边形质心的X和Y,然后可以在脚本中输入这些坐标,并使用.da游标更新其属性表。


您提供的链接似乎在正确的轨道上,但是基本上是我不懂的语言。对于脚本,我不知道输入是什么,也无法解读任何编码以准确了解正在发生的事情。没有什么解释。
Emil Brundage 2015年

0

嗨,我有一个与此类似的问题,所以我虽然给了它一些,但从没有再开始过,但是我只是在想些什么

输入形状

输入形状

我在想你可以在输入形状上创建一个渔网

鱼网 与您相交的鱼网将输入形状

输入区域

然后,您可以计算新处理的多边形内这些宗地的面积

在脚本开始时,区域输入多边形/第n个相等大小的数量

然后,您将需要一种关联宗地的方法,以使宗地知道边界的宗地。

然后,您可以通过行光标汇总包裹

规则被

*它与上一个夏天有一个边界*尚未求和*一旦超过了计算为相等面积的值,它将退后一步,这将是一个组*过程将重新开始*最后一个组可能是剩余的包裹总和

我认为在包裹之间建立关系可能是棘手的事情,但是一旦完成,我认为有可能实现自动化


恐怕我不明白这与我的问题有什么关系。用鱼网切出多边形与在空间上按相等数量对多边形进行分组有什么关系?您似乎专注于区域,而不是数量。宗地多边形的面积(大小)不是一个因素。无论包裹多大或多小,它仍然只是一个与之交谈的财产所有者。参见我的示例,其中红色是农村地区并且分布广泛,而橙色是城市地区,因此覆盖的面积要小得多。
Emil Brundage 2015年

您好,抱歉,我完全误读了您的问题。我认为radouxju帖子可能是要走的路,但是链接有点过头了。将多边形变成点似乎是合乎逻辑的,然后将它们分组。可能存在一种引入道路系统的方法,因为从点到道路的距离和下一个点可能会定义空间元素
Jack Walker


0

这是我针对点事件的解决方案。不能保证它将一直有效...

  1. 在点事件层(调用layer1)上,添加x(双精度),y(双精度)和uniqueid(长整数)的列
  2. 打开第1层的属性表。计算x的x坐标点,y的y坐标点和唯一ID的FID
  3. 执行空间统计工具>映射集群>分组分析
    • 将layer1设置为输入要素
    • 将uniqueid设置为Unique Field ID
    • 定义组数(我们说10个)
    • 选择x和y作为分析字段
    • 选择“ NO_SPATIAL_CONSTRAINT”作为空间约束
    • 点击确定
  4. 执行空间统计工具>测量地理分布>均值中心
    • 从#3中选择输出作为输入要素类
    • 选择SS_Group作为案例字段
    • 点击确定
  5. 打开网络分析师>位置分配工具
    • 加载#4作为设施的输出
    • 将layer1加载为需求点
    • 打开属性并设置
      • 问题类型为最大覆盖能力
      • 10种设施供您选择(来自上面的3)
      • 默认容量,即第1层中要素的总数除以要舍入的设施(因此,如果将145个要素和10个设施/区域设为15,则为四舍五入)
      • 点击确定
        • 解决
        • 您的需求点应该或多或少地平均分配到10个地理区域中

我陷入了您方法的第五步。我已经签出了Network Analyst扩展并添加了Network Analyst工具栏。但是大多数都变灰了,我看不到“位置分配工具”。我正在使用10.1。
埃米尔·布伦达奇

0

您首先需要使用街道创建网络数据集。我尝试过这种建议的方法,到目前为止,最好还是自己对分组(第3步)做同样的事情,对输入字段使用X,Y坐标和k均值(虽然不完美,但更快,更接近我的意思)需要)。我愿意接受其他人的评论和反馈。

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.