【问题标题】:How to generate random geocoordinates using random module如何使用随机模块生成随机坐标
【发布时间】:2021-07-08 08:37:59
【问题描述】:

如何使用 Python 3 random 模块生成随机经纬度?我已经用谷歌搜索并阅读了文档,但没有找到方法。

【问题讨论】:

  • 先生成纬度再生成经度?它没有什么特别之处,AFAIK,它们只是在 -90 到 +90 或 -180 到 +180 之间浮动。
  • 根据您想要的分布,您可能不想随机选择一个统一的纬度 - 这样您会在两极附近得到不成比例的结果。

标签: python random latitude-longitude


【解决方案1】:

使用均匀分布时的问题 纬度和经度 是不是在物理上,纬度不是均匀分布的。

因此,如果您打算将这些随机点用于某些统计平均计算, 或物理蒙特卡洛模拟,结果可能不正确。

如果您绘制“均匀”随机点的图形表示,它们似乎会聚集在极地地区。

想象一下,考虑一下地球上位于纬度 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))

已发现此代码已成功通过上述健全性检查。

【讨论】:

    【解决方案2】:

    在之间生成random number

    Latitude: -85 to +85 (actually -85.05115 for some reason)

    Longitude: -180 to +180

    【讨论】:

    • 假设你想将它们映射到谷歌地图(或者我猜的其他一些墨卡托投影),实际的纬度范围是 -90 和 +90。
    • @Masklinn 不,我查过了,是 -85 到 +85
    • 纬度从 -90° 到 90°。谷歌地图在 -85° 和 85° 左右将地图截断,但这只是因为墨卡托投影在极端纬度地区变得越来越扭曲。它与纬度或地理的运作方式无关。
    • Masklinn 说的是正确的,如果您打算使用墨卡托投影以外的任何其他位置确定位置,您可能应该使用 -90 到 +90。
    【解决方案3】:

    正如@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 位,因为不需要额外的精度。

    【讨论】:

      猜你喜欢
      • 2021-10-03
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 2023-01-07
      • 1970-01-01
      • 2020-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多