如何在python中获取起始坐标和结束坐标之间的'n'个随机点?
How to get 'n' random points between start and end coordinates in python?
我有一个起始坐标 (x1,y1) 和一个结束坐标 (x2, y2)。我想在开始坐标和结束坐标之间生成 'n' 个随机点,不重复。如何用 python 做到这一点?
我知道一个简单的方法是生成 'n' x 值和 'n' y 值。所以我们得到 n*n 对,我选择 'n' 其中没有重复。这样我可能无法得到随机点的均匀分布。还有其他方法吗?
编辑:我需要在由起点坐标和终点坐标作为对角所形成的矩形中的浮点坐标。
TL;DR:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
可以说,实际上:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
return [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
考虑到碰撞的几率很小。
假设“开始坐标和结束坐标之间”是指在笛卡尔坐标系(即平面,2D)中这两个角之间的矩形截面中。
并假设充分忽略了浮点值的 non-uniform 分布,实现了“均匀分布”。 (即,在任何相等长度的间隔上,浮点值的数量不完全相同,连续体中浮点值之间的距离也不恒定)
基本上有三种方法可以确保随机生成的点不重复:
- 从可能值的集合中挑选它们,删除每个选择以避免再次选择它;
- 在允许的 space 范围内生成值,检查每个选择与之前的选择以避免添加重复(和 re-picking 值,直到生成新的值);
- 生成值并添加到集合中直到达到所需的集合大小,生成后删除重复项(如果有)并重复该过程直到完成。
如果从中选取值的 space 的大小与目标集大小相似,则第一个选项可能是一个不错的选择。但是,在某些 space 中选取具有随机浮点坐标的点时,这是不太可能的。
第二个选择是最直接的,但如果目标集大小很大,计算起来可能会很昂贵,因为每个新的选择都会导致更多的比较。
第三个选择有点复杂,但在候选目标集完成之前避免比较,如果碰撞几率很小,当然是最好的选择。
作为第二种选择的变体,您可以选择一个目标数据结构,它可以简单地避免完全重复添加,依靠语言/解释器比用该语言编写的任何算法更有效地执行检查能够。
在 Python 中,这意味着使用 set
而不是 list
,这是获得结果的最快方式,也可能是您要检查的方式无论如何在第三个选项中重复 - 所以你也可以立即使用它并使用第二个选项的变体。
请注意,如果您尝试在大于选择函数域的选择函数范围内创建集合,则第二个和第三个选项都有一个重大缺陷。但是对于给定的问题,除了非常大的 'n'.
之外,这是不太可能的
一个解决方案(将第二个选项与第三个选项进行比较):
from random import uniform
from timeit import timeit
def pick_coords_restricted(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
def pick_coords_checked(x1, y1, x2, y2, n):
result = []
# loops once for attempt, checking after each iteration
while len(set(result)) < n:
if len(result) > 0:
result = list(set(result))
result += [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n - len(result))]
else:
result = [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
return result
print(timeit(lambda: pick_coords_restricted(0, 0, 1, 1, 1000), number=10000))
print(timeit(lambda: pick_coords_checked(0, 0, 1, 1, 1000), number=10000))
结果(在我的硬件上):
4.3799341
3.9363368000000003
pick_coords_checked
函数的结果始终如一,但略好一些 - 我更喜欢第一个实现的清晰度。
我有一个起始坐标 (x1,y1) 和一个结束坐标 (x2, y2)。我想在开始坐标和结束坐标之间生成 'n' 个随机点,不重复。如何用 python 做到这一点?
我知道一个简单的方法是生成 'n' x 值和 'n' y 值。所以我们得到 n*n 对,我选择 'n' 其中没有重复。这样我可能无法得到随机点的均匀分布。还有其他方法吗?
编辑:我需要在由起点坐标和终点坐标作为对角所形成的矩形中的浮点坐标。
TL;DR:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
可以说,实际上:
from random import uniform
def gen_coords(x1, y1, x2, y2, n):
return [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
考虑到碰撞的几率很小。
假设“开始坐标和结束坐标之间”是指在笛卡尔坐标系(即平面,2D)中这两个角之间的矩形截面中。
并假设充分忽略了浮点值的 non-uniform 分布,实现了“均匀分布”。 (即,在任何相等长度的间隔上,浮点值的数量不完全相同,连续体中浮点值之间的距离也不恒定)
基本上有三种方法可以确保随机生成的点不重复:
- 从可能值的集合中挑选它们,删除每个选择以避免再次选择它;
- 在允许的 space 范围内生成值,检查每个选择与之前的选择以避免添加重复(和 re-picking 值,直到生成新的值);
- 生成值并添加到集合中直到达到所需的集合大小,生成后删除重复项(如果有)并重复该过程直到完成。
如果从中选取值的 space 的大小与目标集大小相似,则第一个选项可能是一个不错的选择。但是,在某些 space 中选取具有随机浮点坐标的点时,这是不太可能的。
第二个选择是最直接的,但如果目标集大小很大,计算起来可能会很昂贵,因为每个新的选择都会导致更多的比较。
第三个选择有点复杂,但在候选目标集完成之前避免比较,如果碰撞几率很小,当然是最好的选择。
作为第二种选择的变体,您可以选择一个目标数据结构,它可以简单地避免完全重复添加,依靠语言/解释器比用该语言编写的任何算法更有效地执行检查能够。
在 Python 中,这意味着使用 set
而不是 list
,这是获得结果的最快方式,也可能是您要检查的方式无论如何在第三个选项中重复 - 所以你也可以立即使用它并使用第二个选项的变体。
请注意,如果您尝试在大于选择函数域的选择函数范围内创建集合,则第二个和第三个选项都有一个重大缺陷。但是对于给定的问题,除了非常大的 'n'.
之外,这是不太可能的一个解决方案(将第二个选项与第三个选项进行比较):
from random import uniform
from timeit import timeit
def pick_coords_restricted(x1, y1, x2, y2, n):
result = set()
# loops for each addition, avoiding duplicates
while len(result) < n:
result.add((uniform(x1, x2), uniform(y1, y2)))
return result
def pick_coords_checked(x1, y1, x2, y2, n):
result = []
# loops once for attempt, checking after each iteration
while len(set(result)) < n:
if len(result) > 0:
result = list(set(result))
result += [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n - len(result))]
else:
result = [(uniform(x1, x2), uniform(y1, y2)) for _ in range(n)]
return result
print(timeit(lambda: pick_coords_restricted(0, 0, 1, 1, 1000), number=10000))
print(timeit(lambda: pick_coords_checked(0, 0, 1, 1, 1000), number=10000))
结果(在我的硬件上):
4.3799341
3.9363368000000003
pick_coords_checked
函数的结果始终如一,但略好一些 - 我更喜欢第一个实现的清晰度。