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

时间:2016-05-08 14:38:37

标签: python-3.x numpy multidimensional-array random

假设我们有一个大小为n的空心方形薄片。也就是说,我们有一个n×n平方,从中除去了k * 1矩形(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])

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

3 个答案:

答案 0 :(得分:8)

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

In [350]: llcorners = np.array([[0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2]])

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

In [351]: corner_indices = np.random.choice(len(llcorners), size=size)

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

In [352]: unit_coords = np.random.random(size=(size, 2))

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

In [353]: pts = unit_coords + llcorners[corner_indices]

pts的形状为(size, 2)。这是一个情节,size = 2000

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

plot

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

以下功能将上述想法概括为包含矩形空心的矩形形状。矩形仍然被认为是九个区域,中间区域是空心的。随机点在区域中的概率由该区域的面积决定; 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

例如,

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()

plot

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

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()

plot

答案 1 :(得分:1)

我已经发布了一个较短且不明确的答案, 在这里,我花时间制作了我认为更好的答案。

概括OP问题,我们有一个由nsc * nsr组成的“表面” 布置在nsc列和nsr行中的正方形和一个“洞”组成 设置了nhc * nhr个正方形(对应于表面正方形) 带有nhr行和nhc列的矩形排列 原点位于ohc, ohr

    +------+------+------+------+------+------+------+------+------+ nsr  
    |      |      |      |      |      |      |      |      |      |  
    |      |      |      |      |      |      |      |      |      |  
 ...+------+------+------+------+------+------+------+------+------+ nsr-1  
    |      |      | oooo | oooo |      |      |      |      |      |  
    |      |      | oooo | oooo |      |      |      |      |      |  
    +------+------+------+------+------+------+------+------+------+ ...  
    |      |      | oooo | oooo |      |      |      |      |      |  
    |      |      | oooo | oooo |      |      |      |      |      |  
    +------+------+------+------+------+------+------+------+------+ ...  
    |      |      | oooo | oooo |      |      |      |      |      |  
    |      |      | oooo | oooo |      |      |      |      |      |  
 ohc+------+------+------+------+------+------+------+------+------+ 1  
    |      |      |      |      |      |      |      |      |      |  
    |      |      |      |      |      |      |      |      |      |  
    +------+------+------+------+------+------+------+------+------+ 0  
    0      1      2     ...                         ...   nsc-1   nsc  
                  |             |  
                ohr=2        ohr+nhr

我们的目标是从没有洞的表面绘制n个随机点 (可允许的表面)在...上具有均匀分布 可接受的表面。

我们观察到允许区域由 nsq = nsc*nsr -nhc*nhr等方格: 如果我们在抽象单位平方中放置一个随机点,然后以相同的概率分配 指向可容许区域的一个方格,我们已经完成了 工作

在伪代码中,random()来自均匀分布的随机变量的样本[0, 1)

(x, y) = (random(), random())
square = integer(random()*nsq)
(x, y) = (x, y) + (column_of_square_origin(square), row_of_square_origin(square))

为了加快这个过程,我们正在使用numpy,我们会尽量避免使用for 明确的def origins_of_OK_squares(nsc, nsr, ohc, ohr, nhc, nhr): # a set of tuples, each one the origin of a square, for ALL the squares s_all = {(x, y) for x in range(nsc) for y in range(nsr)} # a set of tuples with the origin of the hole squares s_hole = {(x, y) for x in range(ohc,ohc+nhc) for y in range(ohr,ohr+nhr)} # the set of the origins of admissible squares is the difference s_adm = s_all - s_hole # return an array with all the origins --- the order is not important! # np.array doesn't like sets return np.array(list(s_adm)) 循环。

使用以前使用的名称,我们需要列出其来源 允许的正方形,以实现伪代码的最后一行。

n

我们需要在单位正方形中生成(n,2)个随机点,并以形状 rand_points = np.random.random((n, 2))

的数组进行组织
n

我们需要一组 placements = np.random.randint(0, nsq, n) 允许的正方形

rand_points

我们在placements中翻译其中一个可接受的点 正方形,由 rand_points += origins_of_OK_squares(nsc, nsr, ohc, ohr, nhc, nhr)[placements] 的元素指定。

numpy

利用可能的扩展寻址 import numpy as np def samples_wo_hole(n, nsc, nsr, ohc, ohr, nhc, nhr): s_all = {(x, y) for x in range(nsc) for y in range(nsr)} s_hole = {(x, y) for x in range(ohc,ohc+nhc) for y in range(ohr,ohr+nhr)} rand_points = np.random.random((n, 2)) placements = np.random.randint(0, nsc*nsr - nhc*nhr, n) return rand_points+np.array(list(s_all-s_hole))[placements] 数组,及其完成......

过于紧凑的功能

function loadPicture()
{
  navigator.camera.getPicture(onSuccess, onFail, { destinationType: Camera.DestinationType.FILE_URI,
   sourceType: navigator.camera.PictureSourceType.PHOTOLIBRARY, targetWidth: 200, targetHeight: 200
 });

  function onSuccess(imageURI) {
    var myDate = new Date();
    var date = myDate.getFullYear() +"-" + (myDate.getMonth() + 1)  +"-" + myDate.getUTCDate() +"_" + myDate.getHours() + "-" + myDate.getMinutes() + "-" + myDate.getSeconds();
    var options = new FileUploadOptions();
    var userid = localStorage.getItem("userid");

    options.fileKey = "file";
    options.fileName = "photo-" + userid + "-" + date + ".jpeg";
    options.mimeType = "image/jpeg";
    var params = {};
    params.userid = localStorage.getItem("userid");
    params.date = date;
    params.account = "user";
    options.params = params;

    var ft = new FileTransfer();
    ft.upload(imageURI, encodeURI("http://62.210.192.92/AE/web/upload.php"), win, fail, options);
    navigator.notification.alert("Changement effectué", "", "Photo de profile");
    reload();
    var win = function (r) {}
    var fail = function (error) {}
  }
  function onFail(error) {}
}

答案 2 :(得分:0)

你有8个相等的单位正方形,允许放置点,所以在单位正方形中绘制尽可能多的点,如

x = np.random(n, 2)

现在可以随机选择每个点放置的8个可容纳方格中的哪一个

sq = np.random.randomint(0, 8, n)

你还需要一系列起源

delta = np.array([[0, 0],
                  [1, 0],
                  [2, 0],
                  [0, 1],
                  # no central square
                  [2, 1],
                  [0, 2],
                  [1, 2]
                  [2, 2]])

最后

x = x + delta[sq]

为了概括解决方案,编写一个函数来计算可容许正方形的起源数组,使用集合的可能实现

def origins(n, hole_xor, hole_wd, hole_yor, hole_hg):
    all_origins = {(x,y) for x in range(n) for y in range(n)}
    hole_origins = {(x,y) for x in range(hole_xor, hole_xor+hole_wd)
                          for y in range(hole_yor, hole_yor+hole_hg)}
    return np.array(list(all_origins-hole_origins)))

并像这样使用

delta = origins(12,  4,5,  6,2)
n_squares = len(delta) # or n*n - width*height
target_square = np.random.randomint(0, n_squares, size)
x = x + delta[target_square]