在空心方形层内产生随机均匀分布点的Pythonic方法

Nic*_*sky 4 random numpy multidimensional-array python-3.x

假设我们有一个大小为n的空心方形薄片.也就是说,我们有一个nxn平方,从中删除了ak*l矩形(1 <= k,l <= n-2).我想计算这种空心方形薄层内2个随机均匀分布点之间的距离平均值.为简单起见,我们考虑n = 3,k = l = 1,或3x3平方从中心移除单位正方形

我为numpy编写了这段代码,但它至少有两个问题:我必须丢弃大约1/9的所有生成点并删除numpy.array元素需要大量的RAM:

    x,y = 3*np.random.random((2,size,2))
x = x[
    np.logical_not(np.logical_and(
        np.logical_and(x[:,0] > 1, x[:,0] < 2),
        np.logical_and(x[:,1] > 1, x[:,1] < 2)
        ))
    ]
y = y[
    np.logical_not(np.logical_and(
        np.logical_and(y[:,0] > 1, y[:,0] < 2),
        np.logical_and(y[:,1] > 1, y[:,1] < 2)
        ))
    ]
n = min(x.shape[0], y.shape[0])
Run Code Online (Sandbox Code Playgroud)

UPD:这size是我要计算平均值的样本量.是否有一种优雅的方法可以立即生成这些点,而无需删除不合适的点?

UPD:以下是完整的代码供参考:

def calc_avg_dist(size):
    x,y = 3*np.random.random((2,size,2))
    x = x[
        np.logical_not(np.logical_and(
        np.logical_and(x[:,0] > 1, x[:,0] < 2),
        np.logical_and(x[:,1] > 1, x[:,1] < 2)
        ))
    ]
    y = y[
        np.logical_not(np.logical_and(
        np.logical_and(y[:,0] > 1, y[:,0] < 2),
        np.logical_and(y[:,1] > 1, y[:,1] < 2)
        ))
    ]
    n = min(x.shape[0], y.shape[0])
    diffs = x[:n,:] - y[:n,:]
    return np.sum(np.sqrt(np.einsum('ij,ij->i',diffs,diffs)))/n
Run Code Online (Sandbox Code Playgroud)

War*_*ser 8

移除中心后,有8个区域应包含点.这些是他们的左下角:

In [350]: llcorners = np.array([[0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2]])
Run Code Online (Sandbox Code Playgroud)

这些区域是1x1,因此它们具有相同的区域,并且同样可能包含给定的随机点.以下选择size左下角:

In [351]: corner_indices = np.random.choice(len(llcorners), size=size)
Run Code Online (Sandbox Code Playgroud)

现在size以单位平方生成(x,y)坐标:

In [352]: unit_coords = np.random.random(size=(size, 2))
Run Code Online (Sandbox Code Playgroud)

将它们添加到之前选择的左下角:

In [353]: pts = unit_coords + llcorners[corner_indices]
Run Code Online (Sandbox Code Playgroud)

pts有形状(size, 2).这是一个情节,有size = 2000:

In [363]: plot(pts[:,0], pts[:,1], 'o')
Out[363]: [<matplotlib.lines.Line2D at 0x11000f950>]
Run Code Online (Sandbox Code Playgroud)

情节


更新以解决更新的问题......

以下功能将上述想法概括为包含矩形空心的矩形形状.矩形仍然被认为是九个区域,中间区域是空心的.随机点在区域中的概率由该区域的面积决定; numpy.random.multinomial用于选择每个区域中的点数.

(我确信这个代码有优化的空间.)

from __future__ import division

import numpy as np


def sample_hollow_lamina(size, outer_width, outer_height, a, b, inner_width, inner_height):
    """
    (a, b) is the lower-left corner of the "hollow".
    """
    llcorners = np.array([[0, 0], [a, 0], [a+inner_width, 0],
                          [0, b], [a+inner_width, b],
                          [0, b+inner_height], [a, b+inner_height], [a+inner_width, b+inner_height]])
    top_height = outer_height - (b + inner_height)
    right_width = outer_width - (a + inner_width)
    widths = np.array([a, inner_width, right_width, a, right_width, a, inner_width, right_width])
    heights = np.array([b, b, b, inner_height, inner_height, top_height, top_height, top_height])
    areas = widths * heights
    shapes = np.column_stack((widths, heights))

    regions = np.random.multinomial(size, areas/areas.sum())
    indices = np.repeat(range(8), regions)
    unit_coords = np.random.random(size=(size, 2))
    pts = unit_coords * shapes[indices] + llcorners[indices]

    return pts
Run Code Online (Sandbox Code Playgroud)

例如,

In [455]: pts = sample_hollow_lamina(2000, 5, 5, 1, 1, 2, 3)

In [456]: plot(pts[:,0], pts[:,1], 'o', alpha=0.75)
Out[456]: [<matplotlib.lines.Line2D at 0x116da0a50>]

In [457]: grid()
Run Code Online (Sandbox Code Playgroud)

情节

请注意,参数不必是整数:

In [465]: pts = sample_hollow_lamina(2000, 3, 3, 0.5, 1.0, 1.5, 0.5)

In [466]: plot(pts[:,0], pts[:,1], 'o', alpha=0.75)
Out[466]: [<matplotlib.lines.Line2D at 0x116e60390>]

In [467]: grid()
Run Code Online (Sandbox Code Playgroud)

情节