使用均匀分布时的问题 纬度和经度
是不是在物理上,纬度不是均匀分布的。
因此,如果您打算将这些随机点用于某些统计平均计算,
或物理蒙特卡洛模拟,结果可能不正确。
如果您绘制“均匀”随机点的图形表示,它们似乎会聚集在极地地区。
想象一下,考虑一下地球上位于纬度 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))
健全性检查:
欧几里得几何提供了一个球区概率的公式
由最小/最大纬度和经度定义。对应的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{纬度
或者,反过来:
φ = arcsin (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))
已发现此代码已成功通过上述健全性检查。