如何使用随机模块生成随机地理坐标
How to generate random geocoordinates using random module
如何使用Python3random
模块生成随机经纬度?我已经用谷歌搜索并阅读了文档,但没有找到执行此操作的方法。
在
之间生成一个random number
Latitude: -85 to +85 (actually -85.05115 for some reason)
Longitude: -180 to +180
正如@tandem 在他的回答中所写,纬度的范围几乎是 -90 to +90
(它在地图上被切割),而经度的范围是 -180 to +180
。要生成此范围内的随机浮点数,请使用 random.uniform
函数:
import random
# returns (lat, lon)
def randlatlon():
return (round(random.uniform( -90, 90), 5),
round(random.uniform(-180, 180), 5))
它被四舍五入到逗号后的 5 位数字,因为不需要额外的准确性。
同时纬度和经度使用均匀分布时的问题
是物理上,纬度不是均匀分布的。
因此,如果您打算将这些随机点用于某些统计平均计算之类的事情,
或物理蒙特卡洛模拟,结果可能不正确。
如果绘制“均匀”随机点的图形表示,它们似乎会聚集在极地地区。
为了描绘这一点,请考虑地球上位于纬度 89 到 90 度(北)之间的区域。
一个纬度的长度是 10,000/90 = 111 公里。该区域是一个半径为 111 公里的圆圈,
以北极为中心。其面积约为3.14 * 111 * 111 ≈ 39,000 km2
另一方面,考虑位于纬度 0 到 1 度之间的区域。
这是一条长 40,000 公里(赤道)、宽 111 公里的地带,
所以它的面积是444万平方公里2。比极地大很多
一个简单的算法:
一种可能性是使用 Python 库提供的高斯分布随机变量。
如果我们构建一个 3D 向量,其 3 个分量具有高斯分布,则整体
概率分布就像
exp(-x2) * exp(-y2) * exp(-z2)
但这与 exp(-(x2 + y2 + z2) 是一样的)
或 exp(-r2),其中 r 是距原点的距离。
所以这些向量没有优先方向。一旦归一化为单位长度,它们均匀
分布在单位球面上。他们用纬度分布解决了我们的问题。
想法通过以下Python代码实现:
import math
import random
def randlatlon1():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
# get a random Gaussian 3D vector:
gx = random.gauss(0.0, 1.0)
gy = random.gauss(0.0, 1.0)
gz = random.gauss(0.0, 1.0)
# normalize to an equidistributed (x,y,z) point on the unit sphere:
norm2 = gx*gx + gy*gy + gz*gz
norm1 = 1.0 / math.sqrt(norm2)
x = gx * norm1
y = gy * norm1
z = gz * norm1
radLat = math.asin(z) # latitude in radians
radLon = math.atan2(y,x) # longitude in radians
return (round(cf*radLat, 5), round(cf*radLon, 5))
完整性检查:
欧氏几何提供了球形区域概率的公式
由 minimal/maximal 纬度和经度定义。对应的Python代码是这样的:
def computeProbaG(minLat, maxLat, minLon, maxLon):
pi = math.pi
rcf = pi / 180.0 # degrees to radians Correction Factor
lonProba = (maxLon - minLon) / 360.0
minLatR = rcf * minLat
maxLatR = rcf * maxLat
latProba = (1.0/2.0) * (math.sin(maxLatR) - math.sin(minLatR))
return (lonProba * latProba)
我们还可以通过随机抽样计算相同概率的近似值,使用
randlatlon1
等函数提供的随机点数
他们中的百分比恰好落在所选区域内:
def computeProbaR(randlatlon, ranCount, minLat, maxLat, minLon, maxLon):
norm = 1.0 / ranCount
pairs = [randlatlon() for i in range(ranCount)]
acceptor = lambda p: ( (p[0] > minLat) and (p[0] < maxLat) and
(p[1] > minLon) and (p[1] < maxLon) )
selCount = sum(1 for p in filter(acceptor, pairs))
return (norm * selCount)
有了这两个功能,我们就可以查询各种几何参数集了
几何和概率结果非常吻合,ranCount
设置为一百万个随机点:
ranCount = 1000*1000
print (" ")
probaG1 = computeProbaG( 30, 60, 45, 90)
probaR1 = computeProbaR(randlatlon1, ranCount, 30, 60, 45, 90)
print ("probaG1 = %f" % probaG1)
print ("probaR1 = %f" % probaR1)
print (" ")
probaG2 = computeProbaG( 10, 55, -40, 160)
probaR2 = computeProbaR(randlatlon1, ranCount, 10, 55, -40, 160)
print ("probaG2 = %f" % probaG2)
print ("probaR2 = %f" % probaR2)
print (" ")
执行输出:
$ python3 georandom.py
probaG1 = 0.022877
probaR1 = 0.022852
probaG2 = 0.179307
probaR2 = 0.179644
$
所以这两种数字在这里似乎是一致的。
附录:
为了完整起见,我们可以添加第二个算法,它不太直观,但源自更广泛的统计原理。
要解决纬度分布问题,我们可以使用Inverse Transform Sampling定理。为此,我们需要一些公式来计算纬度小于任意指定值的概率,φ.
纬度小于给定 φ 的单位 3D 球体区域称为 球冠。它的面积可以通过初等微积分得到,例如here
球冠面积由公式给出:A = 2π * (1 + sin(φ))
将这个面积除以单位3D球体的总面积即4π即可得到相应的概率,对应φ=φmax=π/2。因此:
p = Proba{latitude < φ} = (1/2) * (1 + sin(φ))
或者,反过来:
φ = 反正弦 (2*p - 1)
根据逆变换采样定理,通过将概率p替换为在0和1之间均匀分布的随机变量,可以获得纬度(以弧度为单位)的公平采样。在 Python 中,这给出:
lat = math.asin(2*random.uniform(0.0, 1.0) - 1.0)
至于经度,这是一个独立的随机变量,仍然均匀分布在-π和+π之间(以弧度为单位)。所以整体 Python 采样器代码是:
def randlatlon2r():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
u0 = random.uniform(0.0, 1.0)
u1 = random.uniform(0.0, 1.0)
radLat = math.asin(2*u0 - 1.0) # angle with Equator - from +pi/2 to -pi/2
radLon = (2*u1 - 1) * pi # longitude in radians - from -pi to +pi
return (round(radLat*cf,5), round(radLon*cf,5))
已发现此代码已成功通过上述完整性检查。
如何使用Python3random
模块生成随机经纬度?我已经用谷歌搜索并阅读了文档,但没有找到执行此操作的方法。
在
之间生成一个random numberLatitude: -85 to +85 (actually -85.05115 for some reason)
Longitude: -180 to +180
正如@tandem 在他的回答中所写,纬度的范围几乎是 -90 to +90
(它在地图上被切割),而经度的范围是 -180 to +180
。要生成此范围内的随机浮点数,请使用 random.uniform
函数:
import random
# returns (lat, lon)
def randlatlon():
return (round(random.uniform( -90, 90), 5),
round(random.uniform(-180, 180), 5))
它被四舍五入到逗号后的 5 位数字,因为不需要额外的准确性。
同时纬度和经度使用均匀分布时的问题 是物理上,纬度不是均匀分布的。
因此,如果您打算将这些随机点用于某些统计平均计算之类的事情, 或物理蒙特卡洛模拟,结果可能不正确。
如果绘制“均匀”随机点的图形表示,它们似乎会聚集在极地地区。
为了描绘这一点,请考虑地球上位于纬度 89 到 90 度(北)之间的区域。 一个纬度的长度是 10,000/90 = 111 公里。该区域是一个半径为 111 公里的圆圈, 以北极为中心。其面积约为3.14 * 111 * 111 ≈ 39,000 km2
另一方面,考虑位于纬度 0 到 1 度之间的区域。 这是一条长 40,000 公里(赤道)、宽 111 公里的地带, 所以它的面积是444万平方公里2。比极地大很多
一个简单的算法:
一种可能性是使用 Python 库提供的高斯分布随机变量。 如果我们构建一个 3D 向量,其 3 个分量具有高斯分布,则整体 概率分布就像 exp(-x2) * exp(-y2) * exp(-z2) 但这与 exp(-(x2 + y2 + z2) 是一样的) 或 exp(-r2),其中 r 是距原点的距离。
所以这些向量没有优先方向。一旦归一化为单位长度,它们均匀 分布在单位球面上。他们用纬度分布解决了我们的问题。
想法通过以下Python代码实现:
import math
import random
def randlatlon1():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
# get a random Gaussian 3D vector:
gx = random.gauss(0.0, 1.0)
gy = random.gauss(0.0, 1.0)
gz = random.gauss(0.0, 1.0)
# normalize to an equidistributed (x,y,z) point on the unit sphere:
norm2 = gx*gx + gy*gy + gz*gz
norm1 = 1.0 / math.sqrt(norm2)
x = gx * norm1
y = gy * norm1
z = gz * norm1
radLat = math.asin(z) # latitude in radians
radLon = math.atan2(y,x) # longitude in radians
return (round(cf*radLat, 5), round(cf*radLon, 5))
完整性检查:
欧氏几何提供了球形区域概率的公式 由 minimal/maximal 纬度和经度定义。对应的Python代码是这样的:
def computeProbaG(minLat, maxLat, minLon, maxLon):
pi = math.pi
rcf = pi / 180.0 # degrees to radians Correction Factor
lonProba = (maxLon - minLon) / 360.0
minLatR = rcf * minLat
maxLatR = rcf * maxLat
latProba = (1.0/2.0) * (math.sin(maxLatR) - math.sin(minLatR))
return (lonProba * latProba)
我们还可以通过随机抽样计算相同概率的近似值,使用
randlatlon1
等函数提供的随机点数
他们中的百分比恰好落在所选区域内:
def computeProbaR(randlatlon, ranCount, minLat, maxLat, minLon, maxLon):
norm = 1.0 / ranCount
pairs = [randlatlon() for i in range(ranCount)]
acceptor = lambda p: ( (p[0] > minLat) and (p[0] < maxLat) and
(p[1] > minLon) and (p[1] < maxLon) )
selCount = sum(1 for p in filter(acceptor, pairs))
return (norm * selCount)
有了这两个功能,我们就可以查询各种几何参数集了
几何和概率结果非常吻合,ranCount
设置为一百万个随机点:
ranCount = 1000*1000
print (" ")
probaG1 = computeProbaG( 30, 60, 45, 90)
probaR1 = computeProbaR(randlatlon1, ranCount, 30, 60, 45, 90)
print ("probaG1 = %f" % probaG1)
print ("probaR1 = %f" % probaR1)
print (" ")
probaG2 = computeProbaG( 10, 55, -40, 160)
probaR2 = computeProbaR(randlatlon1, ranCount, 10, 55, -40, 160)
print ("probaG2 = %f" % probaG2)
print ("probaR2 = %f" % probaR2)
print (" ")
执行输出:
$ python3 georandom.py
probaG1 = 0.022877
probaR1 = 0.022852
probaG2 = 0.179307
probaR2 = 0.179644
$
所以这两种数字在这里似乎是一致的。
附录:
为了完整起见,我们可以添加第二个算法,它不太直观,但源自更广泛的统计原理。
要解决纬度分布问题,我们可以使用Inverse Transform Sampling定理。为此,我们需要一些公式来计算纬度小于任意指定值的概率,φ.
纬度小于给定 φ 的单位 3D 球体区域称为 球冠。它的面积可以通过初等微积分得到,例如here
球冠面积由公式给出:A = 2π * (1 + sin(φ)) 将这个面积除以单位3D球体的总面积即4π即可得到相应的概率,对应φ=φmax=π/2。因此:
p = Proba{latitude < φ} = (1/2) * (1 + sin(φ))
或者,反过来:
φ = 反正弦 (2*p - 1)
根据逆变换采样定理,通过将概率p替换为在0和1之间均匀分布的随机变量,可以获得纬度(以弧度为单位)的公平采样。在 Python 中,这给出:
lat = math.asin(2*random.uniform(0.0, 1.0) - 1.0)
至于经度,这是一个独立的随机变量,仍然均匀分布在-π和+π之间(以弧度为单位)。所以整体 Python 采样器代码是:
def randlatlon2r():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
u0 = random.uniform(0.0, 1.0)
u1 = random.uniform(0.0, 1.0)
radLat = math.asin(2*u0 - 1.0) # angle with Equator - from +pi/2 to -pi/2
radLon = (2*u1 - 1) * pi # longitude in radians - from -pi to +pi
return (round(radLat*cf,5), round(radLon*cf,5))
已发现此代码已成功通过上述完整性检查。