2014-11-11 3 views
0

У меня есть файл формы ESRI Point Shape с (среди других) поле nMSLINK и поле DIAMETER. MSLINK не уникален из-за пространственного соединения. То, что я хочу достичь, - сохранить только функции в шейп-файле, которые имеют уникальное значение MSLINK и наименьшее значение DIAMETER вместе с соответствующими значениями в других полях. Я могу использовать поисковый курсор для достижения этого (перебирать все функции и удалять каждую функцию, которая не соответствует, но это занимает много времени (> 75000 функций). Мне было интересно, может ли, например, numpy сделать трюк быстрее в ArcMap/arcpy.Сохраняйте наименьшее значение для каждого уникального идентификатора с дуговым/numpy

+1

Можете ли вы добавить код для минимального примера? – atomh33ls

+0

'# Выберите наименьшее MIDDELLIJN_INWENDIG для каждого MSLINK' ' строк = arcpy.SearchCursor ('Afsluiters_Leidingen', '', '', '', 'MSLINK A; MIDDELLIJN_INWENDIG D') '' для строки в строках: ' \t 'диам = row.MIDDELLIJN_INWENDIG' \t' ДИКТ [row.MSLINK] = diam' 'для ключа в Словаре:' ' \t arcpy.SelectLayerByAttribute_management ('Afsluiters_Leidingen', 'NEW_SELECTION', 'MSLINK =' + ул (key) + 'AND NOT MIDDELLIJN_INWENDIG =' + str (dict [key])) ' \t' arcpy.DeleteFeatures_management ('Afsluiters_Leidingen') ' –

+0

Это работает, но требуется возраст для больших шейп-файлов –

ответ

0

Я думаю, что такая обработка будет намного быстрее, если вы будете работать с памятью, а не взаимодействовать с arcgis. Например, поместив все строки сначала в объект python (возможно, namedTuple будет хорошим вариантом здесь) .Тогда вы можете узнать, какие строки вы хотите удалить или вставить.

Самый быстрый подход зависит от: a) если у вас много повторных строк (MSLINK), то самым быстрым будет вставка только тех, которые вы необходимо в новом слое. Или b) если строки, которые нужно удалить, всего несколько, по сравнению с общим количеством строк, то удаление происходит быстрее.

Для a) вам нужно получить все поля в кортеж, включая координаты точки, чтобы вы могли просто создать новый класс объектов и вставить новые строки.

# 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 + ['[email protected]'] 

# 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 поля, уникальный идентификатор, MSLINK и диаметр. Затем создайте список удаления (здесь вам понадобятся только уникальные идентификаторы). Затем снова запустите класс объектов и удалите строки с идентификатором в списке delete. Чтобы быть уверенным, я бы сначала дублировал класс объектов и работал над копией.

0

Есть несколько шагов, которые вы можете предпринять, чтобы выполнить эту задачу более эффективно. Прежде всего, использование курсора анализатора данных, в отличие от старой версии курсора, увеличит скорость вашего процесса. Предполагается, что вы работаете в 10.1 или выше. Затем вы можете использовать сводную статистику, а именно ее способность находить минимальное значение, основанное на поле случая. Для вашего поля case будет nMSLINK.

В приведенном ниже коде создается таблица статистики со всеми уникальными значениями «nMSLINK» и соответствующим минимальным значением «ДИАМЕТР». Затем я использую таблицу select, чтобы выделять только строки в таблице, чье поле FREQUENCY не равно 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» является строковым полем, а «ДИАМЕТР» - числовым.

Код имеет следующие входы:

Feature: Функция для анализа

Workspace: Папка, которая будет хранить пару промежуточных таблиц временно

TempTableName1: Имя для одной временной таблицы ,

TempTableName2: Имя для второй временной таблицы

FIELD1 = The неединственное поле

Field2 = поле с числовыми значениями, которые вы хотите, чтобы найти самые низкие из

Код:

# 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) 

Это должно быть быстрее, чем прямой курсор. Дайте мне знать, если это имеет смысл. Удачи!

+0

Я проверил свой метод с очень большим набором данных, и он был ненадежным. В частности, конечная строка SQL становится слишком большой и вызывает проблемы. Я также тестировал метод andzep, и он работал отлично. Я рекомендую его метод. –

Смежные вопросы

 Смежные вопросы