Элегантный поиск сетки в python/numpy - программирование
Подтвердить что ты не робот

Элегантный поиск сетки в python/numpy

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

param1_list = [p11, p12, p13,...]
param2_list = [p21, p22, p23,...] # not necessarily the same number of values
...

results_size = (len(param1_list), len(param2_list),...)
results = np.zeros(results_size, dtype = np.float)

for param1_idx in range(len(param1_list)):
  for param2_idx in range(len(param2_list)):
    ...
    param1 = param1_list[param1_idx]
    param2 = param2_list[param2_idx]
    ...
    results[param1_idx, param2_idx, ...] = my_func(param1, param2, ...)

max_index = np.argmax(results) # indices of best parameters!

Я хочу сохранить первую часть, где я определяю списки как есть, так как я хочу легко манипулировать значениями, по которым я ищу.

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

Бит в середине, однако, довольно повторяющийся и громоздкий (особенно потому, что у меня много параметров, и я могу добавить или удалить параметры), и я чувствую, что должен быть более сжатый/элегантный способ инициализировать матрицу результатов, перебрать все индексы и установить соответствующие параметры.

Итак, есть?

4b9b3361

Ответ 1

Я думаю, scipy.optimize.brute - это то, что вам нужно.

>>> from scipy.optimize import brute
>>> a,f,g,j = brute(my_func,[param1_list,param2_list,...],full_output = True)

Обратите внимание, что если аргумент full_output равен True, возвращается сетка оценки.

Ответ 3

Решение John Vinyard кажется правильным; но если вы ищете большую гибкость, вы можете использовать трансляцию + vectorize. Используйте ix_ для создания широковещательного набора параметров, а затем передайте их в векторизованную версию функции (но см. Ниже):

a, b, c = range(3), range(3), range(3)
def my_func(x, y, z):
    return (x + y + z) / 3.0, x * y * z, max(x, y, z)

grids = numpy.vectorize(my_func)(*numpy.ix_(a, b, c))
mean_grid, product_grid, max_grid = grids

Со следующими результатами для mean_grid:

array([[[ 0.        ,  0.33333333,  0.66666667],
        [ 0.33333333,  0.66666667,  1.        ],
        [ 0.66666667,  1.        ,  1.33333333]],

       [[ 0.33333333,  0.66666667,  1.        ],
        [ 0.66666667,  1.        ,  1.33333333],
        [ 1.        ,  1.33333333,  1.66666667]],

       [[ 0.66666667,  1.        ,  1.33333333],
        [ 1.        ,  1.33333333,  1.66666667],
        [ 1.33333333,  1.66666667,  2.        ]]])

product grid:

array([[[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],

       [[0, 0, 0],
        [0, 1, 2],
        [0, 2, 4]],

       [[0, 0, 0],
        [0, 2, 4],
        [0, 4, 8]]])

и max grid:

array([[[0, 1, 2],
        [1, 1, 2],
        [2, 2, 2]],

       [[1, 1, 2],
        [1, 1, 2],
        [2, 2, 2]],

       [[2, 2, 2],
        [2, 2, 2],
        [2, 2, 2]]])

Обратите внимание, что это может быть не самый быстрый подход. vectorize удобен, но он ограничен скоростью переданной ему функции, а функции python медленны. Если вы могли бы переписать my_func, чтобы использовать numpy ufuncs, вы могли бы получить свои сетки быстрее, если бы вам было интересно. Что-то вроде этого:

>>> def mean(a, b, c):
...     return (a + b + c) / 3.0
... 
>>> mean(*numpy.ix_(a, b, c))
array([[[ 0.        ,  0.33333333,  0.66666667],
        [ 0.33333333,  0.66666667,  1.        ],
        [ 0.66666667,  1.        ,  1.33333333]],

       [[ 0.33333333,  0.66666667,  1.        ],
        [ 0.66666667,  1.        ,  1.33333333],
        [ 1.        ,  1.33333333,  1.66666667]],

       [[ 0.66666667,  1.        ,  1.33333333],
        [ 1.        ,  1.33333333,  1.66666667],
        [ 1.33333333,  1.66666667,  2.        ]]])

Ответ 4

Вы можете использовать numpy meshgrid для этого:

import numpy as np

x = range(1, 5)
y = range(10)

xx, yy = np.meshgrid(x, y)
results = my_func(xx, yy)

обратите внимание, что ваша функция должна работать с numpy.array s.