Python 使用arcpy/numpy为每个唯一ID保留最小值

Python 使用arcpy/numpy为每个唯一ID保留最小值,python,numpy,unique,arcpy,arcmap,Python,Numpy,Unique,Arcpy,Arcmap,我有一个ESRI点形状文件,其中包括一个nMSLINK字段和一个直径字段。由于空间连接,MSLINK不是唯一的。我想要实现的是只保留shapefile中具有唯一MSLINK和最小直径值的特征,以及其他字段中的相应值。我可以使用searchcursor在所有功能中循环并删除每个不符合要求的功能,但这需要使用超过75000个功能。我想知道numpy是否可以在ArcMap/arcpy中更快地完成这项任务。我认为,如果您使用内存而不是与arcgis交互,那么进行这种处理肯定会快得多。例如,通过将所有行放

我有一个ESRI点形状文件,其中包括一个nMSLINK字段和一个直径字段。由于空间连接,MSLINK不是唯一的。我想要实现的是只保留shapefile中具有唯一MSLINK和最小直径值的特征,以及其他字段中的相应值。我可以使用searchcursor在所有功能中循环并删除每个不符合要求的功能,但这需要使用超过75000个功能。我想知道numpy是否可以在ArcMap/arcpy中更快地完成这项任务。

我认为,如果您使用内存而不是与arcgis交互,那么进行这种处理肯定会快得多。例如,通过将所有行放在python对象的第一位,在这里使用namedtuple可能是一个不错的选择。然后,您可以找到要删除或插入的行

最快的方法取决于一个新的层。如果你有很多MSLINK重复行,那么最快的方法就是在新层中插入你需要的行。或者b如果要删除的行与行总数相比只是少数,则删除速度更快

对于图形,需要将所有字段(包括点坐标)提取到元组中,以便创建新要素类并插入新行

# Example of Variant a:

from collections import namedtuple

# assuming the following:
source_fc # contains name of the fclass
the_path # contains path to the shape
cleaned_fc # the name of the cleaned fclass


# use all fields of source_fc plus the shape token to get a touple with xy
# coordinates (using 'mslink' and 'diam' here to simplify the example)
fields = ['mslink', 'diam', 'field3', ... ]
all_fields = fields + ['SHAPE@XY']

# define a namedtuple to hold and work with the rows, use the name 'point' to
# hold the coordinates-tuple
Row = namedtuple('Row', fields + ['point'])
data = []
with arcpy.da.SearchCursor(source_fc, fields) as sc:
    for r in sc:
        # unzip the values from each row into a new Row (namedtuple) and append
        # to data
        data.append(Row(*r))

# now just delete the rows we don't want, for this, the easiest way, is probably
# to order the tuple first after MSLINK and then after the diamater...
data = sorted(data, key = lambda x : (x.mslink, x.diam))

# ... now just keep the first ones for each mslink
to_keep = []
last_mslink = None
for d in data:
    if last_mslink != d.mslink:
        last_mslink = d.mslink
        to_keep.append(d)

# create a new feature class with the same fields as the source_fc
arcpy.CreateFeatureclass_management(
        out_path=the_path, out_name=cleaned_fc, template=source_fc)
with arcpy.da.InsertCursor(cleaned_fc, all_fields) as ic:
    for r in to_keep:
        ic.insertRow(*r)

对于备选方案b,我只获取3个字段,一个唯一ID、MSLINK和直径。然后在这里创建一个删除列表,您只需要唯一的ID。然后在要素类中再次循环并删除删除列表中id为的行。为了确保这一点,我会先复制要素类,然后复制一个副本

为了更有效地完成这项任务,您可以采取以下几个步骤。首先也是最重要的一点是,与旧版本的游标相反,使用data analyst游标将提高流程的速度。这假设您使用的是10.1或更高版本。然后,您可以使用摘要统计,即它能够根据案例字段找到最小值。对于您的,案例字段将是nMSLINK

下面的代码首先创建一个统计表,其中包含所有唯一的“nMSLINK”值及其对应的最小“直径”值。然后,我使用一个表select只选择表中“频率”字段不是1的行。从这里开始,我遍历我的新表,并开始构建一个字符串列表,这些字符串将构成最终的sql语句。在这个迭代之后,我使用python连接函数创建一个sql字符串,如下所示:

("nMSLINK" = 'value1' AND "DIAMETER" <> 624.0) OR ("nMSLINK" = 'value2' AND "DIAMETER" <> 1302.0) OR ("nMSLINK" = 'value3' AND "DIAMETER" <> 1036.0) ...
sql选择nMSLINK值不唯一且直径值不是最小值的行。使用此SQL,我按属性选择并删除所选行

编写此SQL语句时,假设要素类位于文件地理数据库中,“nMSLINK”是字符串字段,“DIAMETER”是数字字段

该代码具有以下输入:

特征:要分析的特征

工作区:临时存储两个中间表的文件夹

试探性名称1:一个临时表的名称

试探性名称2:第二个临时表的名称

Field1=非均匀场

Field2=包含您希望从中找到最低值的数值的字段

代码:


这应该比直接向上的光标快。让我知道这是否有意义。祝你好运

你能为一个简单的例子添加一些代码吗?为每个MSLINK行选择最小的MIDDELLIJN\u INWENDIG=arcpy.SearchCursor'Afsluiters\u Leidingen','MSLINK A;MIDDELLIJN_INWENDIG D'代表行中的行:diam=row.MIDDELLIJN_INWENDIG dict[row.MSLINK]=diam代表行中的键:arcpy.SelectLayerByAttribute_管理'Afsluiters_Leidingen'、'NEW_SELECTION'、'MSLINK='+strkey+'而不是MIDDELLIJN_INWENDIG='+strict[key]arcpy.DeleteFeatures_管理'Afsluiters_Leidingen'这项工作,但是,对于大型形状文件,需要花费很长时间。我用一个非常大的数据集测试了我的方法,结果不可靠。具体来说,最后一个SQL字符串太大,会导致问题。我还测试了安德泽普的方法,他的方法效果很好。我推荐他的方法。
# Import modules
from arcpy import *
import os
# Local variables

#Feature to analyze
Feature = r"C:\E1B8\ScriptTesting\Workspace\Workspace.gdb\testfeatureclass"
#Workspace to export table of identicals
Workspace = r"C:\E1B8\ScriptTesting\Workspace"
#Name of temp DBF table file
TempTableName1 = "Table1"
TempTableName2 = "Table2"

#Field names
Field1 = "nMSLINK" #nonunique
Field2 = "DIAMETER" #field with numeric values

#Make layer to allow selection
MakeFeatureLayer_management (Feature, "lyr")

#Path for first temp table
Table = os.path.join (Workspace, TempTableName1)

#Create statistics table with min value
Statistics_analysis (Feature, Table, [[Field2, "MIN"]], [Field1])

#SQL Select rows with frequency not equal to one
sql = '"FREQUENCY" <> 1'
# Path for second temp table
Table2 = os.path.join (Workspace, TempTableName2)
# Select rows with Frequency not equal to one
TableSelect_analysis (Table, Table2, sql)

#Empty list for sql bits
li = []

# Iterate through second table
cursor = da.SearchCursor (Table2, [Field1, "MIN_" + Field2])
for row in cursor:
    # Add SQL bit to list
    sqlbit = '("' + Field1 + '" = \'' + row[0] + '\' AND "' + Field2 + '" <> ' + str(row[1]) + ")"
    li.append (sqlbit)
del row
del cursor

#Create SQL for selection of unwanted features
sql = " OR ".join (li)
print sql
#Select based on SQL
SelectLayerByAttribute_management ("lyr", "", sql)

#Delete selected features
DeleteFeatures_management ("lyr")

#delete temp files
Delete_management ("lyr")
Delete_management (Table)
Delete_management (Table2)