簡體   English   中英

如何生成橢圓柱,用隨機分布的點填充它,並測量 R 中這些點之間的重疊實例

[英]How to generate an elliptical cylinder, populate it with randomly distributed points, and measure instances of overlap between those points in R

我想確定隨機分布的 A 型 object 占據或接觸(重疊)與填充在橢圓柱內的任何隨機分布的 B 型 object 相同的空間的概率。 然后我想多次循環此模擬以生成更可靠的概率值。

我可以使用形狀 package 繪制橢圓柱:

library(shape)
emptyplot(c(-5, 5), c(-15, 15), main = "filled elliptic cylinder")
filledcylinder(rx = 9, ry = 5, len= 2, angle = 00, col = "white",  
               lcol = "black", lcolint = "grey") 

我不知道如何向該圖中添加點(即對象 A 和 B)。 但是,我懷疑圖形表達不是完成此任務的 go 的方式(盡管我發現可視化很有幫助)。 我懷疑更好的方法是創建一個 function 來描述橢圓柱,類似於以下示例中的圓錐體,並在沒有圖形 output 的情況下運行模擬:

# Create a function to describe a cone
cone <- function(x, y){
  sqrt(x ^ 2 + y ^ 2)
}

# prepare variables.
x <- y <- seq(-1, 1, length = 30)
z <- outer(x, y, cone)

# plot as a 3D surface for visual reference (even though I actually want a volume)
persp(x, y, z,
      main="Perspective Plot of a Cone",
      zlab = "Height",
      theta = 30, phi = 15,
      col = "orange", shade = 0.4)

可悲的是,我不知道如何為我的橢圓柱做這個。 我從以下來源知道用於描述橢圓柱的參數:

https://mathworld.wolfram.com/EllipticCylinder.html

不幸的是,我不太了解它。 我希望我的填充圓筒中給出的尺寸可以作為指導。 最終維度值並不重要,重要的是可以輸入值的代碼結構。

至於對象:

假設有 50 個 A 類對象和 50 個 B 類對象,其大小為 x=0.4、y=0.4、z=0.4(與我的圖形橢圓柱示例中的單位相同)。

所有物體都將隨機分布在橢圓柱的體積內,除了類型 A 的物體不能與另一個類型 A object 重疊,類型 B 的物體不能與其他類型 B 的物體重疊。類型 A 物體可能與 B 類對象重疊。

我想要 output 在給定體積中與任何 B 型 object 重疊的 A 型對象的數量,這個數字占 A 型對象總數的百分比,以及每次模擬運行的所有對象總數的百分比。

我什至不知道如何開始這樣做。

如果你能幫忙,恐怕需要向(不是特別聰明的)孩子解釋統計、幾何和非基礎 R 表達式。

非常感謝您的寶貴時間!

帶有大量注釋代碼的實現以進行解釋。 這假定 A 型和 B 型對象必須完全位於橢圓柱內。

library(data.table)

rObj <- function(rx, ry, h, n, dims, eps = 2) {
  # Function to create a random sample (by rejection) of non-overlapping
  # rectangular prism objects inside an elliptical cylinder whose ellipse is
  # centered at x = 0, y = 0 and whose height ranges from -dims[3]/2 to h -
  # dims[3]/2. The objects have dimensions (x, y, z) = dims, and all edges are
  # parallel or orthogonal to each of the x, y, or z axes.
  # INPUTS:
  #   rx:   length of the ellipse
  #   ry:   width of the ellipse
  #   h:    height of the elliptical cylinder
  #   n:    number of non-overlapping objects to return
  #   dims: dimensions of the rectangular prism objects (vector of length 3)
  #   eps:  oversampling factor
  # OUTPUT: a data.table with 3 columns and n rows. Each row gives the
  #         coordinates of the centroid of a sampled object
  dt <- data.table()
  while(nrow(dt) < n) {
    # increase oversampling if it is not the first pass
    if (nrow(dt)) eps <- eps*2
    rho <- sqrt(runif(eps*n))
    phi <- runif(eps*n, 0, 2*pi)
    dt <- data.table(
      # sample object centroids
      # see https://stackoverflow.com/questions/5529148/algorithm-calculate-pseudo-random-point-inside-an-ellipse
      # First, uniformly sample on an ellipse centered on x = 0, y = 0,
      # with xlength = rx - dims[1] and ylength = ry - dims[2]
      # (any object with a centroid outside of this ellipse will stick out of
      # the elliptical cylinder, although some with a centroid within the
      # smaller ellipse will still stick out of the elliptical cylinder).
      x = (rx - dims[1])/2*rho*cos(phi),
      y = (ry - dims[2])/2*rho*sin(phi),
      # uniformly sample centroid heights
      z = runif(eps*n, 0, h - dims[3])
    )[
      # remove objects that stick out of bounds
      # The ellipse satisfies (x/(rx/2))^2 + (y/(ry/2))^2 = 1, which is the
      # same as (x/rx)^2 + (y/ry)^2 = 0.25. Taking advantage of symmetry, add
      # half of the x and y dimensions of the objects to the absolute value of
      # x and y (the object corner furthest from the foci of the ellipse) and
      # check if the result satisfies the standard equation.
      ((abs(x) + dims[1]/2)/rx)^2 + ((abs(y) + dims[2]/2)/ry)^2 < 0.25
    ][
      # remove objects that overlap a previously placed object
      # Since each rectangular prism object is oriented with the x, y, z axes,
      # two objects overlap if they are closer than their lengths in each
      # dimension.
      tabulate(
        sequence((.N - 1L):1, 2:.N)[ # row numbers (always keep the first row)
          (dist(x) < dims[1]) & (dist(y) < dims[2]) & (dist(z) < dims[3])
        ],
        .N
      ) == 0L
    ]
  }
  dt[1:n] # keep the first n objects
}

# function to get pairwise distances between two vectors
dist2 <- function(x, y) abs(outer(x, y, "-"))

fsim <- function(rx, ry, h, nA, nB, dimA, dimB, nreps, eps = 2) {
  # function to simulate placement of A and B rectangular prism objects inside
  # an elliptical cylinder and count the number of A-type objects that
  # intersect at least one B-type object. All object edges are parallel or
  # orthogonal to each of the x, y, or z axes.
  
  # INPUTS:
  #   rx:     length of the ellipse
  #   ry:     width of the ellipses
  #   h:      height of the elliptical cylinder
  #   nA:     number of non-overlapping A-type objects to return
  #   nB:     number of non-overlapping B-type objects to return
  #   dimX:   dimensions of the rectangular prism objects (vector of length 3)
  #   nreps:  the number of replications to simulate
  #   eps:    oversampling factor when randomly sampling non-overlapping objects
  #           by rejection
  # OUTPUT: vector of length "nreps" giving the number of A-type objects that
  # intersect at least one B-type object for each replication
  dims <- rowMeans(cbind(dimA, dimB)) # average dimensions of the A and B objects
  out <- integer(nreps) # initialize the output vector
  # repeat the simulation "nreps" times
  for (i in 1:nreps) {
    # get the coordinates of the A- and B-type objects' centroids
    A <- rObj(rx, ry, h, nA, dimA, eps)
    B <- rObj(rx, ry, h, nB, dimB, eps)
    # count the number of A-type objects that intersect at least one B-type
    # object
    out[i] <- sum(rowSums((dist2(A$x, B$x) < dims[1])*(dist2(A$y, B$y) < dims[2])*(dist2(A$z, B$z) < dims[3])) != 0L)
  }
  
  out
}

時間 10K 模擬復制:

system.time(overlaps <- fsim(9, 5, 2, 50L, 50L, rep(0.4, 3), rep(0.4, 3), 1e4L))
#>    user  system elapsed 
#>   27.19    0.25   27.67
mean(overlaps)
#> [1] 18.7408

獲得此問題的近似答案的一種方法是將事物離散化。 將體積設置為零的 3 維數組,然后一次隨機生成一個形狀的參數。

對於每個生成的形狀,找到該形狀內的所有數組元素。 如果任何位置在圓柱體之外或與相同類型的形狀重疊,請重試。 一旦你有一個合法的形狀,標記那些數組條目(例如 1 代表類型 A,2 代表類型 B)。 首先做所有類型 A,然后所有類型 B,並記錄形狀 B 占據先前標記為形狀 A 的空間的次數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM