假设我们有一个大小为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
答案 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>]
更新以解决更新后的问题...
以下功能将上述想法概括为包含矩形空心的矩形形状。矩形仍然被认为是九个区域,中间区域是空心的。随机点在区域中的概率由该区域的面积决定; 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()
请注意,参数不必是整数:
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()
答案 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]