См. Важные разъяснения внизу этого вопроса.
Я использую numpy для ускорения обработки координат долготы / широты. К сожалению, из-за моих «неловких» оптимизаций мой код выполнялся примерно в 5 раз медленнее , чем без использования numpy.
Узким местом является заполнение массива с моими данными, а затем извлечение этих данных после выполнения математических преобразований. Для заполнения массива у меня в основном есть цикл вроде:
point_list = GetMyPoints() # returns a long list of ( lon, lat ) coordinate pairs
n = len( point_list )
point_buffer = numpy.empty( ( n, 2 ), numpy.float32 )
for point_index in xrange( 0, n ):
point_buffer[ point_index ] = point_list[ point_index ]
Этот цикл, просто заполняющий массив NumPy, прежде чем даже работать с ним, чрезвычайно медленный, намного медленнее, чем все вычисления без NUMPY. (То есть, это не просто медлительность самого цикла python, а, по-видимому, некоторые огромные издержки при передаче каждого небольшого блока данных из python в numpy.) На другом конце есть аналогичная медлительность; после того, как я обработал пустые массивы, я получаю доступ к каждой измененной координатной паре в цикле, снова как
some_python_tuple = point_buffer[ index ]
Опять же, этот цикл для извлечения данных намного медленнее, чем все исходные вычисления без кучи. Итак, как мне на самом деле заполнить массив NumPy и извлечь данные из массива NUMPY таким образом, чтобы это не противоречило цели использования NUMPY?
Я читаю данные из файла формы, используя библиотеку C, которая передает мне данные в виде обычного списка Python. Я понимаю, что если бы библиотека передавала мне координаты уже в массиве NumPy, не было бы необходимости в "заполнении" NUMPY массива. Но, к сожалению, отправной точкой для меня с данными является обычный список питонов. И что еще важнее, в общем, я хочу понять, как вы быстро заполняете массивный массив данными из Python.
Разъяснение
Показанный выше цикл на самом деле упрощен. Я написал это таким образом в этом вопросе, потому что я хотел сосредоточиться на проблеме, которую я видел, пытаясь медленно заполнить пустой массив в цикле. Теперь я понимаю, что это медленно.
В моем реальном приложении у меня есть файл формы координатных точек, и у меня есть API для получения точек для данного объекта. Есть что-то вроде 200 000 объектов. Поэтому я неоднократно вызываю функцию GetShapeCoords( i )
, чтобы получить координаты для объекта i. Это возвращает список списков, где каждый подсписок представляет собой список пар lon / lat, и причина в том, что это список списков, состоит в том, что некоторые объекты состоят из нескольких частей (то есть, многоугольника). Затем в моем исходном коде, когда я читал в точках каждого объекта, я выполнял преобразование для каждой точки, вызывая обычную функцию python, а затем строил графики преобразованных точек, используя PIL. На рисование всех 200 000 полигонов ушло около 20 секунд. Не ужасно, но много возможностей для улучшения. Я заметил, что, по крайней мере, половина из этих 20 секунд была потрачена на выполнение логики преобразования, поэтому я решил, что сделаю это просто. И моя первоначальная реализация состояла в том, чтобы просто читать объекты по одному и продолжать добавлять все точки из подсписков в один большой массив numpy, который я затем мог бы выполнять математически в numpy.
Итак, теперь я понимаю, что простая передача всего списка python в numpy - это правильный способ создать большой массив. Но в моем случае я читаю только один объект за раз. Поэтому я мог бы добавлять точки в большой список списков списков на языке Python. И затем, когда я скомпилировал таким образом большое количество точек объектов (скажем, 10000 объектов), я мог просто назначить этот список монстров numpy.
Итак, мой вопрос состоит из трех частей:
(a) Правда ли, что numpy может взять этот большой список списков неправильной формы и быстро и быстро его проглотить?
(b) Затем я хочу иметь возможность трансформировать все точки в листьях этого дерева монстров.Например, к какому выражению придумать «войти в каждый подсписок, а затем в каждый подсписок, а затем для каждой пары координат, которую вы найдете в этих подсписках, умножить первую (координату lon) на 0.5»?Могу ли я это сделать?
(c) Наконец, мне нужно вывести эти преобразованные координаты обратно, чтобы построить их.
Ответ Уинстона, приведенный ниже, кажется, дает некоторый намек на то, как я могу это сделатьвсе это с помощью itertools.То, что я хочу сделать, во многом похоже на то, что делает Уинстон, сглаживая список.Но я не могу просто сгладить это.Когда я иду рисовать данные, мне нужно знать, когда один полигон останавливается, а следующий начинается.Итак, я думаю, я мог бы заставить его работать, если бы был способ быстро пометить конец каждого многоугольника (то есть каждого подсписка) специальной парой координат, например (-1000, -1000) или что-то в этом роде.Тогда я мог бы сгладить с помощью itertools, как в ответе Уинстона, и затем сделать преобразования в numpy.Затем мне нужно рисовать из точки в точку, используя PIL, и здесь я думаю, что мне нужно переназначить измененный массив numpy обратно в список python, а затем перебрать этот список в обычном цикле python для рисования.Похоже, это мой лучший вариант, кроме написания модуля C, который бы обрабатывал все операции чтения и рисования за один шаг?