【问题标题】:Elegant grid search in python/numpypython/numpy中的优雅网格搜索
【发布时间】:2012-11-02 11:05:15
【问题描述】:

我有一个有一堆参数的函数。我不想手动设置所有参数,而是执行网格搜索。我有每个参数的可能值列表。对于每个可能的参数组合,我想运行我的函数来报告我的算法在这些参数上的性能。我想将这个结果存储在一个多维矩阵中,以便之后我可以找到最大性能的索引,这反过来又会给我最好的参数。下面是现在的代码编写方式:

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!

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

我还想以原样结束结果矩阵,因为我将可视化更改不同参数如何影响算法的性能。

不过,中间那段是相当重复和庞大的(特别是因为我有很多参数,我可能想添加或删除参数),我觉得应该有一个更简洁/优雅的方式来初始化结果矩阵,遍历所有索引,并设置适当的参数。

那么,有吗?

【问题讨论】:

标签: python numpy


【解决方案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,则将返回评估网格。

【讨论】:

  • 我稍微简化了上面的情况。我实际上报告了多个值作为输出(几个评估函数),所以我的结果行是 results[p1idx, p2idx, ... , :, :, :] = 3d 输出值矩阵。因此,我认为我不能使用 scipy 的蛮力搜索。您的解决方案完全正确地解决了我上面发布的问题,但我正在寻找方法来简化该代码以创建结果矩阵,而无需借助现有的 gridsearch 函数。
  • 您是否正在尝试为许多标量输出之一找到最佳输入参数,例如“给我最小化结果 [i] 的输入”,或者您有一些一次评估所有结果的“优点”的方法,比如总和,或者 l1 或 l2 范数?
  • 这些值是各种对象的准确率、精度和召回率。我将严格控制每个对象类别内和对象之间的准确度,并以各种方式结合准确率和召回率度量。
  • @diants /John- 我正在解决一个类似的问题。由于您将以多种方式组合参数,因此您的 myfunct 将具有组合优化功能,对吗?像 a >=0.7 ,找到 b 的最小值和 c 的最大值 => min(a)+max(b)+a>=0.7 ==> {min(a)+min(-b)+(a-0.7 )>0 } >0 a+(-b)+(-1)*(a-0.7)}
  • 我把问题贴在这里,stackoverflow.com/questions/23993422/…请考虑回答。
【解决方案2】:

John VinyardSibelius Seraphini 的解决方案是很好的内置选项,但如果您希望获得更大的灵活性,您可以使用广播 + 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.        ]]])

【讨论】:

    【解决方案3】:

    您可以使用 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'])
    

    【讨论】:

    • 新版模块:from sklearn.model_selection import ParameterGrid
    • 另外,如果您想为网格的某些参数添加随机化,您可以使用:sklearn.model_selection.ParameterSampler 而不是 ParameterGrid
    【解决方案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.arrays。

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 2019-03-25
      • 2019-12-06
      • 2020-09-11
      • 1970-01-01
      • 2017-09-09
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多