在 R^n 中对 cube/sphere 进行网格搜索

Grid search over a cube/sphere in R^n

我正在尝试对 R^n 中的球体实施网格搜索(在 Python 中,如果重要的话),其中 n 未知。

输入包括球体的半径和中心,以及控制网格分辨率的超参数 theta。我想将这个球体中的每个点表示为这三个参数的函数。

我也愿意考虑立方体搜索,只迭代立方体的面。 (即迭代 L_inf sphere

如果我知道n=2,我会做的是:

import numpy as np

def enumerate_2d_sphere(R,theta,center=(0,0)):
    for n in xrange(int(2*np.pi / theta)+1):
        degree = n*theta
        point =(center[0]+R*np.cos(degree),center[1]+R*np.sin(degree))
        yield point

for p in enumerate_2d_sphere(1,0.1):
    print p

由于 n 可以任意大,我正在寻找一种有效地迭代 sphere\cube 的方法。

有什么想法吗?

+++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++

我最终使用了 strubbly 建议的修改版本:

import itertools
import numpy as np
import matplotlib.pyplot as plt

def f(d, center, scale=1):
    dim = len(center)
    print d/-2.0
    diff = scale * np.array([d/-2.0 for _ in xrange(dim)])
    bias = diff + center
    for i in range(dim):
        l = ([ xrange(1,d) for _ in xrange(i)] +
             [[0,d]] +
             [ xrange(d+1) for _ in xrange(dim-i-1)]
            )
        for r in itertools.product(*l):
            yield scale*np.array(r)+bias
#example for R^2:
center = (1,1.5)
data = np.array([x for x in f(20,center,scale = 0.1)])


plt.scatter(data[:,0], data[:,1],color='r',s=100,alpha=0.5)
plt.scatter(center[0], center[1],color='b',s=300,alpha=0.5)
plt.show()

输出图:

还有一个选择,就是生成 uniformly distributed samples on the sphere。请注意,样本数控制点的 "density"(或预期密度):

import numpy as np
def generate_random_points(R,center,quantity=1000):
    """
    :param R: float
    :param center: np.array
    :param quantity: int
    """
    dim = len(center)
    for n in xrange(quantity):
        s = np.random.normal(0, 1,dim)
        r = np.sqrt(np.dot(s,s))
        s = (R/r) * s
        yield s+center

最糟糕的方法(就简单性和效率而言)是使用 enumeration of n-1 angles 在球体上生成点。缺乏效率是因为需要经常计算产品 sincos(尽管这也可以被黑客攻击)

我认为 sklearn 网格搜索功能没有这个选项,但手动实现这个应该不难

  • 迭代 n 的值
  • 对于每个 n,以从 0 到 360 的 theta 步幅迭代 n 个不同的角度参数
  • 如果您不需要球体体积,也可以迭代半径 - 如果您只需要表面,请保持半径不变

您可以使用 n 维球面坐标(例如 wikipedia),或者您可以使用欧氏坐标,只需将最后一个坐标设置为获得正确半径(正负)所需的任何值即可.这两个都是很好的参数化,将为您提供球体上的所有点 - 使用正确数量的参数进行迭代。

但它们不会自然地导致恒定面积(体积)元素 - 仅考虑 3 球体就很容易看出这一点。这个问题没有简单的解决方案。

我认为一种可能的方法是使用 n-1 维网格参数化,但根据体积将第 n 个分量细分为可变数量的值。

n立方体的面更简单:只需生成第n个坐标为最小或最大的n对面。因此,例如,考虑从原点开始的大小为 1 的 n 维立方体:

将第一个坐标设置为零,并在其余坐标上枚举一个网格。然后将其设置为一个并再次执行。然后重复第二个坐标。等等。

这是使用 itertools.product 执行此操作的简单方法。为了简单和高效,我已将框缩放为整数坐标:您需要重新缩放并移动中心。所以 n 是维数,d 是沿每个轴的细分数。

import itertools

def f(n,d):

    for i in range(n):
        l = ([ range(1,d-1) for _ in range(i)] +
             [[0,d-1]] +
             [ range(d) for _ in range(n-i-1)]
            )
        for r in itertools.product(*l):
            yield r

print(list(f(4,3)))