代码之家  ›  专栏  ›  技术社区  ›  denis

生成像城市一样分布的随机点?

  •  5
  • denis  · 技术社区  · 15 年前

    如何产生1000个随机点,分布类似于 俄亥俄州的城镇?
    恐怕我不能准确地定义“像城市一样分布”; 均匀分布中心+小高斯云 很容易但是很特别。
    附加:必须有一个二维分布族 一个聚类参数可以改变以匹配给定的点集?

    4 回复  |  直到 13 年前
        1
  •  2
  •   Volker Stolz    15 年前

    也许你可以看看沃尔特·克里斯塔勒的 Theory of Central Places 是的。我想某个地方一定有发电机,否则你可以自己做。

        2
  •  2
  •   Doug McClean    15 年前

    从目标区域的水景模型开始(如果是虚构的地方,也可以做一个模型),然后将靠近河流交汇处的城市,沿着湖岸,湖泊河流交汇处聚集起来。然后建造连接那些主要城市的假想公路。现在,在这些公路上以合理的间距喷洒一些中间城市,最好靠近公路的交叉点。现在在空旷的空地上撒上一些小镇。

        3
  •  1
  •   denis    15 年前

    具有poisson簇大小的高斯簇工作得相当好。

    问题:生成与给定城市大致相似的随机点,例如在美国。

    子问题:
    a)用行数描述集群,使“集群A类似于集群B” 简化为“clusternumbers(a)类似于“clusternumbers(b)”。
    运行n=100,然后通过下面的fcluster运行1000点,ncluster=25,给出

    N 100 ncluster 25: 22 + 3  r 117
    sizes: av 4     10   9   8   7   6   6   5   5   4   4   4 ...
    radii: av 117  202 198 140 134  64  62  28 197 144 148 132 ...
    
    N 1000 cluster 25: 22 + 3  r 197
    sizes: av 45  144 139 130  85  84  69  63  43  38  33  30  ...
    radii: av 197  213 279 118 146 282 154 245 212 243 226 235 ...
    

    b)找出具有2个或3个参数的随机生成器的组合 它可以改变以产生不同的簇。
    具有poisson簇大小的高斯簇可以很好地匹配城市的簇:

    def randomclusters( N, ncluster=25,  radius=1, box=box ):
        """ -> N 2d points: Gaussian clusters, Poisson cluster sizes """
        pts = []
        lam = eval( str( N // ncluster ))
        clustersize = lambda: np.random.poisson(lam - 1) + 1
            # poisson 2:  14  27  27  18   9   4  %
            # poisson 3:   5  15  22  22  17  10  %
        while len(pts) < N:
            u = uniformrandom2(box)
            csize = clustersize()
            if csize == 1:
                pts.append( u )
            else:
                pts.extend( inbox( gauss2( u, radius, csize )))
        return pts[:N]
    
    
        # Utility functions --
    
    import scipy.cluster.hierarchy as hier
    
    def fcluster( pts, ncluster, method="average", criterion="maxclust" ):
        """ -> (pts, Y pdist, Z linkage, T fcluster, clusterlists)
            ncluster = n1 + n2 + ... (including n1 singletons)
            av cluster size = len(pts) / ncluster
        """
            # Clustering is pretty fast:
            # sort pdist, then like Kruskal's MST, O( N^2 ln N )
            # Many metrics and parameters are possible; these satisfice.
        pts = np.asarray(pts)
        Y = scipy.spatial.distance.pdist( pts )  # N*(N-1)/2
        Z = hier.linkage( Y, method )  # N-1, like mst
        T = hier.fcluster( Z, ncluster, criterion=criterion )
        clusters = clusterlists(T)
        return (pts, Y, Z, T, clusters)
    
    def clusterlists(T):
        """ T = hier.fcluster( Z, t ) e.g. [a b a b c a]
            -> [ [0 2 5] [1 3] ] sorted by len, no singletons [4]
        """
        clists = [ [] for j in range( max(T) + 1 )]
        for j, c in enumerate(T):
            clists[c].append( j )
        clists.sort( key=len, reverse=True )
        n1 = np.searchsorted(  map( len, clists )[::-1], 2 )
        return clists[:-n1]
    
    def radius( x ):
        """ rms |x - xmid| """
        return np.sqrt( np.mean( np.var( x, axis=0 )))
            # * 100  # 1 degree lat/long ~ 70 .. 111 km
    
        4
  •  1
  •   aioobe    9 年前

    在Java中,这是通过 new Random().nextGaussian() 是的。由于Java源代码是可用的,您可以查看它:

    synchronized public double nextGaussian() {
        // See Knuth, ACP, Section 3.4.1 Algorithm C.
        if (haveNextNextGaussian) {
            haveNextNextGaussian = false;
            return nextNextGaussian;
        } else {
            double v1, v2, s;
            do {
                v1 = 2 * nextDouble() - 1; // between -1 and 1
                v2 = 2 * nextDouble() - 1; // between -1 and 1
                s = v1 * v1 + v2 * v2;
            } while (s >= 1 || s == 0);
            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
            nextNextGaussian = v2 * multiplier;
            haveNextNextGaussian = true;
            return v1 * multiplier;
        }
    }
    

    利用

    x = r.nextGaussian() * rad/4 + rad;
    y = r.nextGaussian() * rad/4 + rad;
    

    这座美丽的城市:

    enter image description here