Вложенные ленивые списки Python

Я пытаюсь построить двумерное изображение с помощью matplotlib, которое ожидает точки данных в формате вложенного списка. У меня есть очень аккуратный, идиоматический способ создать это:

zs = [[cost_at(x, y) for x in x_range] for y in y_range]
plt.contourf(x_range, y_range, zs, 1000)

И это работает — для небольших данных. Однако теперь мне нужно сделать то же самое, за исключением того, что диапазоны X и Y слишком велики, чтобы полный вложенный список поместился в памяти. Мне кажется, что должна быть возможность вызывать API с ленивыми списками, которые, надеюсь, будут адекватной заменой, предполагая, что библиотека обращается к ним с помощью итераторов.

Как можно сделать вышеперечисленное, кроме как с ленивыми списками?


person rwallace    schedule 19.12.2017    source источник
comment
Что происходит с вложенным списком? Это происходит очень медленно? Итак, вы в основном хотели бы оптимизировать время выполнения?   -  person    schedule 19.12.2017
comment
@J.C.Rocamonde Диапазоны значений X и Y слишком велики, чтобы весь вложенный список поместился в памяти   -  person Bahrom    schedule 19.12.2017
comment
Мне кажется, должна быть возможность вызывать API с помощью ленивых списков - что говорится в документации для plt.contourf()?   -  person John Coleman    schedule 19.12.2017
comment
Ленивая версия понимания списка была бы эквивалентным выражением генератора!   -  person juanpa.arrivillaga    schedule 20.12.2017
comment
Чтобы построить контурный график, все данные должны быть известны сразу. Хотя технически можно, конечно, написать контурный алгоритм, который работает с частью данных, окружающих вычисляемую в данный момент область, внутри matplotlib работает иначе. Также в таком алгоритме вы бы не работали со строками и столбцами данных. При этом способ создания контурного графика заключается в предоставлении массива numpy. В случае, если массив numpy будет слишком большим для памяти, разумное сшивание массива в более мелкие части может быть способом.   -  person ImportanceOfBeingErnest    schedule 20.12.2017
comment
@ImportanceOfBeingErnest Я попробовал пустой массив. Хорошая новость, это работает. Плохая новость, это не уменьшает потребление памяти. На самом деле это выглядит так, потому что почти вся память используется внутри matplotlib.   -  person rwallace    schedule 20.12.2017
comment
Нет, это не уменьшит память, в том массиве те же числа, что и в списке списков. Возникает вопрос, как уменьшить потребление памяти при построении контурного графика? В этом случае можно было бы начать думать о том, сколько данных действительно необходимо. Если данные настолько велики, что заполняют всю память современного компьютера, наверняка найдется способ получить тот же визуальный результат, но с гораздо меньшим объемом данных.   -  person ImportanceOfBeingErnest    schedule 20.12.2017


Ответы (1)


В Python «ленивый список» можно создать с помощью выражения генератора:

zs = ((cost_at(x, y) for x in x_range) for y in y_range)

Используя круглые скобки вместо квадратных, вы создаете вложенное генераторное выражение, которое выдает cost_at(x, y) по одному вместо того, чтобы вычислять их все сразу.

person Hai Vu    schedule 19.12.2017
comment
Аккуратное решение! К сожалению, plt.contourf не принимает генераторы, но это все еще отличное решение для других контекстов. Спасибо! - person rwallace; 20.12.2017
comment
Разве это не очень сбивает с толку, чтобы принять ответ, который в конечном итоге не работает? Таким образом, будущие читатели будут думать, что они могут использовать генераторы для построения контурных графиков с помощью matplotlib, но это не так. - person ImportanceOfBeingErnest; 20.12.2017
comment
@ImportanceOfBeingErnest Вот почему я добавил этот комментарий. Не то чтобы я ожидаю альтернативного ответа, который работает с matplotlib. - person rwallace; 20.12.2017