Оптимизация кода Python для больших данных


34

У меня есть код Python, который предназначен для принятия точечных шейп-файлов через следующий рабочий процесс:

  1. Точки слияния
  2. Объедините точки так, чтобы любые точки в пределах 1 м друг от друга становились одной точкой
  3. Создать векторный слой, где выбраны точки с z <10
  4. Буферные очки
  5. Разрешение полигона на растр 1м
  6. Реклассифицировать, где 1 - 9 = 1; NoData = 0

Каждый шейп-файл имеет от 250 000 до 350 000 точек, покрывающих ~ 5x7 км. Точечные данные, используемые в качестве входных данных, представляют собой местоположения деревьев. Каждая точка (т. Е. Дерево) имеет соответствующее значение "z", которое представляет радиус короны и используется в процессе буферизации. Мое намерение состоит в том, чтобы использовать окончательный двоичный вывод в отдельном процессе, чтобы создать растр, описывающий покрытие купола.

Я провел тест с четырьмя шейп-файлами, и он создал растр 700 МБ и занял 35 минут (процессор i5 и 8 ГБ ОЗУ). Видя, что мне нужно будет запустить этот процесс на 3500 шейп-файлах, я был бы признателен за любые советы по оптимизации этого процесса (см. Прилагаемый код). Вообще говоря, как лучше всего справиться с геообработкой больших данных? В частности, есть ли какие-либо изменения в коде или рабочем процессе, которые могут помочь повысить эффективность?

Редактировать :

Время (% от общего) для задач геообработки:

  • Слияние = 7,6%
  • Интеграция = 7,1%
  • Особенность к Lyr = 0
  • Буфер = 8,8%
  • Поли в растр = 74,8%
  • Реклассифицировать = 1,6%

введите описание изображения здесь

# Import arcpy module
import arcpy

# Check out any necessary licenses
arcpy.CheckOutExtension("spatial")

# Script arguments
temp4 = arcpy.GetParameterAsText(0)
if temp4 == '#' or not temp4:
    temp4 = "C:\\gdrive\\temp\\temp4" # provide a default value if unspecified

Reclassification = arcpy.GetParameterAsText(1)
if Reclassification == '#' or not Reclassification:
    Reclassification = "1 9 1;NODATA 0" # provide a default value if unspecified

Multiple_Value = arcpy.GetParameterAsText(2)
if Multiple_Value == '#' or not Multiple_Value:
    Multiple_Value = "C:\\t1.shp;C:\\t2.shp;C:\\t3.shp;C:\\t4.shp" # provide a default value if unspecified

# Local variables:
temp_shp = Multiple_Value
Output_Features = temp_shp
temp2_Layer = Output_Features
temp_Buffer = temp2_Layer
temp3 = temp_Buffer

# Process: Merge
arcpy.Merge_management(Multiple_Value, temp_shp, "x \"x\" true true false 19 Double 0 0 ,First,#,C:\\#########omitted to save space

# Process: Integrate
arcpy.Integrate_management("C:\\gdrive\\temp\\temp.shp #", "1 Meters")

# Process: Make Feature Layer
arcpy.MakeFeatureLayer_management(temp_shp, temp2_Layer, "z <10", "", "x x VISIBLE NONE;y y VISIBLE NONE;z z VISIBLE NONE;Buffer Buffer VISIBLE NONE")

# Process: Buffer
arcpy.Buffer_analysis(temp2_Layer, temp_Buffer, "z", "FULL", "ROUND", "NONE", "")

# Process: Polygon to Raster
arcpy.PolygonToRaster_conversion(temp_Buffer, "BUFF_DIST", temp3, "CELL_CENTER", "NONE", "1")

# Process: Reclassify
arcpy.gp.Reclassify_sa(temp3, "Value", Reclassification, temp4, "DATA")

3
Возможно, стоит добавить некоторый код синхронизации производительности, чтобы определить, идет ли большая часть времени на один или несколько шагов, чтобы на них можно было сфокусироваться, чтобы попытаться найти прирост производительности
PolyGeo

5
Я не думаю, что у вас есть много вариантов для повышения производительности, если вы продолжаете использовать ArcPy. Может быть, вы можете посмотреть на другие инструменты, чтобы сделать это? Инструменты, такие как FME или, возможно, postgis?
tmske

3
Непонятно, какой тип пикселя используется, но если это «байт» (что и должно быть), то хранилище необработанных данных будет 5000x7000 = 35 МБ (~ 33,4 МБ) на растр, что на самом деле не так уж и велико. Однако следующее измерение 3500 (измерение времени?) Увеличивает общий необработанный размер до ~ 114 ГБ.
Майк Т

5
Хотя я не могу сказать из этого описания, что алгоритм делает (или намеревался сделать), в большинстве случаев буферы точек, за которыми следует растеризация, должны быть заменены растеризацией точек, за которой следует фокусная статистика (обычно среднее значение или сумма). Результат будет таким же, но, избегая длительных шагов буферизации и поли растеризации, он будет получен намного быстрее. Я (сильно) подозреваю, что могут быть получены существенные дополнительные ускорения, но я не могу дать конкретный совет из-за неопределенности описания процедуры.
whuber

2
Буферы вокруг точек имеют переменный размер (в зависимости от значения точки z). Я думаю, что для того, чтобы по-прежнему выполнять фокусную статистику, вам придется разделить результирующие точки на величину z и делать растровые и фокусные характеристики для каждого набора (используя z в качестве радиуса в круговой окрестности с максимумом в качестве стат). Затем запустите Cell Cell для всех 9 растров с максимальной статистикой, чтобы объединить результаты. (Что, вероятно, все еще намного быстрее, чем буфер и растеризация с большим набором данных.)
blord-castillo

Ответы:


10

Некоторые изменения алгоритма, которые должны вам помочь.

Выполните ваш выбор, прежде чем объединить или интегрировать. Это значительно сократит расходы на более поздние функции.

Слияние и интеграция требуют больших затрат памяти, поэтому вы хотите продолжать исключать функции по мере того, как вы вводите классы пространственных объектов, и пытаться выполнять слияния в двоичном дереве, чтобы сохранить размер слияний и интеграций. например, для четырех шейп-файлов вы объединяете два шейп-файла и интегрируете их; объединить еще два шейп-файла и интегрировать; объединить два результирующих класса объектов и интегрировать.

Ваша очередь заданий начинается как очередь ссылок на шейп-файл. У вас также есть очередь результатов для размещения результатов. Метод run () для вашего работника параллельной обработки выполняет следующие операции: убирает из очереди два элемента. Если ничего не занято (очередь пуста), завершите работу. Если один элемент взят, поместите этот элемент прямо в очередь результатов.

Если для каждого элемента выбраны два элемента: если это шейп-файл, выберите для z <10 и создайте класс объектов in_memory; иначе, это уже класс объектов in_memory и пропускает шаг выбора. Объедините два класса объектов in_memory, чтобы создать новый класс объектов in_memory. Удалите исходные два класса объектов. Выполните интегрирование в новый класс пространственных объектов. Поместите этот класс объектов в очередь результатов.

Затем запустите внешний цикл while. Цикл начинается с очереди шейп-файла и проверяется на длину, превышающую 1. Затем он проходит очередь через рабочих. Если очередь результатов имеет длину больше 1, цикл while выполняет еще одну параллельную обработку, выполняемую для рабочих, пока очередь результатов не станет равной 1 классу объектов in_memory.

Например, если вы начинаете с 3500 шейп-файлов, ваша первая очередь будет иметь 3500 заданий. Второй будет иметь 1750 рабочих мест. 875, 438, 219, 110, 55, 28, 14, 7, 4, 2, 1. Ваше большое узкое место будет памятью. Если вам не хватает памяти (и вам не хватит памяти при создании первой очереди результатов, если это так), то измените ваш алгоритм, чтобы объединить более 2 классов объектов одновременно, а затем интегрируйте, что сократит размер вашей первой очереди результатов в обмен на более длительное время обработки. При желании вы можете написать выходные файлы и пропустить, используя классы объектов in_memory. Это значительно замедлит вас, но поможет преодолеть узкое место в памяти.

Только после выполнения слияния и интеграции всех шейп-файлов, заканчивающихся одним классом пространственных объектов, вы затем выполняете буферизацию, поли-растр и переклассификацию. Таким образом, эти три операции выполняются только один раз, и вы сохраняете свою геометрию простой.


+1 за использование рабочей области in_memory, если ваши данные поместятся в память. Это значительно ускоряет операции геообработки.
RyanDalton

Это хорошая вещь. Я думаю, что это может быть даже лучше с диаграммой и некоторым psuedocode (или реальным кодом!).
blah238

Да, я бы хотел, чтобы у меня было время посвятить себя написанию кода. В любом случае мне нужно написать новый демонстрационный скрипт параллельной обработки.
Blord-Castillo

14

Первое, что я хотел бы сделать, это отслеживать использование ресурсов вашей системы с помощью Resource Monitor в Windows 7 или perfmon в Vista / XP, чтобы понять, привязаны ли вы к процессору , памяти или IO .

Если вы ограничены памятью или вводом-выводом, вы, вероятно, очень мало что можете сделать, кроме как модернизировать оборудование, уменьшить размер проблемы или полностью изменить подход.

Если вы решите, что вы привязаны к процессору, я бы поэкспериментировал с multiprocessingмодулем или с одним из множества других доступных пакетов параллельной обработки на основе Python , чтобы посмотреть, сможете ли вы использовать больше ядер процессора для ускорения ваших операций.

Хитрость многопроцессорности и параллелизма в целом заключается в нахождении хорошей схемы разбиения, которая:

  1. Позволяет разделить входные данные на более мелкие рабочие наборы, а затем объединить результаты таким образом, который имеет смысл,
  2. Добавляет наименьшее количество накладных расходов (некоторые неизбежны по сравнению с последовательной обработкой), и
  3. Позволяет настроить размер рабочего набора, чтобы наилучшим образом использовать ресурсы системы для оптимальной производительности.

Вы можете использовать сценарий, который я создал в этом ответе, в качестве отправной точки: Портировать код Avenue для создания Building Shadows в ArcPy / Python для ArcGIS Desktop?

Смотрите также этот блог ESRI, посвященный геообработке, на тему: Мультипроцессинг Python - подходы и соображения.

Я думаю, что ваш случай будет еще более сложным из-за более «черного ящика» природы используемых вами инструментов, а не из-за более мелкозернистых геометрических массивов, с которыми я работал. Возможно, работа с массивами NumPy может пригодиться.

Я также наткнулся на некоторые интересные материалы для чтения, если вы хотите посмотреть дальше arcpy:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.