优雅的网格搜索python/numpy

dla*_*nts 20 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!
Run Code Online (Sandbox Code Playgroud)

我想保留第一部分,我按原样定义列表,因为我希望能够轻松地操作我搜索的值.

我还希望最终得到结果矩阵,因为我将可视化更改不同参数如何影响算法的性能.

但是,中间的位是相当重复和笨重的(特别是因为我有很多参数,我可能想添加或删除参数),我觉得应该有一个更简洁/优雅的方式来初始化结果矩阵,迭代所有索引,并设置适当的参数.

那么,有吗?

Sib*_*ini 25

您可以使用sklearn模块中的ParameterGrid

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'])
Run Code Online (Sandbox Code Playgroud)

  • 新版本的模块:`来自sklearn.model_selection导入ParameterGrid` (7认同)

Joh*_*ard 10

我想scipy.optimize.brute你正在追求的是什么.

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

请注意,如果full_output参数为True,则将返回评估网格.


sen*_*rle 6

John Vinyard的解决方案似乎是正确的; 但如果您正在寻求更大的灵活性,可以使用广播+ vectorize.使用ix_产生broadcastable组参数,然后这些信息传递给函数的向量化版本(但看到下面的警告):

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
Run Code Online (Sandbox Code Playgroud)

以下结果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.        ]]])
Run Code Online (Sandbox Code Playgroud)

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]]])
Run Code Online (Sandbox Code Playgroud)

并且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]]])
Run Code Online (Sandbox Code Playgroud)

请注意,这可能不是最快的方法.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.        ]]])
Run Code Online (Sandbox Code Playgroud)