Элегантный поиск сетки в 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!
Я хочу сохранить первую часть, где я определяю списки как есть, так как я хочу легко манипулировать значениями, по которым я ищу.
Я также хочу получить матрицу результатов как есть, так как я буду визуализировать, как изменение разных параметров влияет на производительность алгоритма.
Бит в середине, однако, довольно повторяющийся и громоздкий (особенно потому, что у меня много параметров, и я могу добавить или удалить параметры), и я чувствую, что должен быть более сжатый/элегантный способ инициализировать матрицу результатов, перебрать все индексы и установить соответствующие параметры.
Итак, есть?
Ответы
Ответ 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
, возвращается сетка оценки.
Ответ 2
Вы можете использовать ParameterGrid из модуля sklearn
http://scikit-learn.org/stable/modules/generated/sklearn.grid_search.ParameterGrid.html
Пример
from sklearn.grid_search import ParameterGrid
param_grid = {'param1': [value1, value2, value3], 'paramN' : [value1, value2, valueM]}
grid = ParameterGrid(param_grid)
for params in grid:
your_function(params['param1'], params['param2'])
Ответ 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.