Làm thế nào để tạo ra các giá trị phân phối đồng đều trong một khoảng hiệu quả?


12

Giả sử tôi muốn tạo một tập hợp các số ngẫu nhiên từ khoảng (a, b). Trình tự được tạo cũng phải có thuộc tính mà nó được sắp xếp. Tôi có thể nghĩ ra hai cách để đạt được điều này.

Đặt nđộ dài của chuỗi được tạo.

Thuật toán thứ 1:

Let `offset = floor((b - a) / n)`
for i = 1 up to n:
   generate a random number r_i from (a, a+offset)
   a = a + offset
   add r_i to the sequence r

Thuật toán thứ 2:

for i = 1 up to n:
    generate a random number s_i from (a, b)
    add s_i to the sequence s
sort(r)

Câu hỏi của tôi là, thuật toán 1 có tạo ra các chuỗi tốt như các thuật toán được tạo bởi thuật toán 2 không?


BTW thật dễ dàng để tạo một danh sách các số ngẫu nhiên được sắp xếp trong R. Để tạo một mảng gồm tập hợp số ngẫu nhiên trong một khoảng thống nhất , đoạn mã sau hoạt động : . kn[a,b]rand_array <- replicate(k, sort(runif(n, a, b))
RobertF

Câu trả lời:


18

Thuật toán đầu tiên thất bại nặng nề vì hai lý do:

  1. Lấy sàn của có thể giảm đáng kể. Thật vậy, khi , nó sẽ bằng 0, cho bạn một tập hợp có giá trị hoàn toàn giống nhau!(ab)/nba<n

  2. Khi bạn không lấy sàn, các giá trị kết quả được phân bổ quá đều . Chẳng hạn, trong bất kỳ mẫu ngẫu nhiên đơn giản nào của iid thống nhất biến thiên (giả sử giữa và ), có cơ hội lớn nhất sẽ không nằm trong khoảng trên từ đến . Với thuật toán 1, có khả năng tối đa sẽ nằm trong khoảng đó. Đối với một số mục đích, tính đồng nhất này là tốt, nhưng nói chung đó là một lỗi khủng khiếp vì (a) nhiều số liệu thống kê sẽ bị hủy hoại nhưng (b) có thể rất khó xác định lý do tại sao.na=0b=1(11/n)n1/e37%11/n1100%

  3. Nếu bạn muốn tránh sắp xếp, thay vào đó hãy tạo các biến thiên phân bố theo cấp số nhân độc lập . Bình thường hóa tổng tích lũy của chúng cho phạm vi bằng cách chia cho tổng. Giảm giá trị lớn nhất (sẽ luôn là ). Rescale đến phạm vi .n+1(0,1)1(a,b)

Biểu đồ của cả ba thuật toán được hiển thị. (Mỗi mô tả kết quả tích lũy của bộ độc lập1000n=100

Để biết thêm nhiều cách (gây cười) để mô phỏng các biến thể đồng phục độc lập, hãy xem Mô phỏng rút ra từ Phân phối thống nhất bằng cách sử dụng các lần rút từ Phân phối chuẩn .

Hình: biểu đồ

Đây là Rmã đã tạo ra con số.

b <- 1
a <- 0
n <- 100
n.iter <- 1e3

offset <- (b-a)/n
as <- seq(a, by=offset, length.out=n)
sim.1 <- matrix(runif(n.iter*n, as, as+offset), nrow=n)
sim.2 <- apply(matrix(runif(n.iter*n, a, b), nrow=n), 2, sort)
sim.3 <- apply(matrix(rexp(n.iter*(n+1)), nrow=n+1), 2, function(x) {
  a + (b-a) * cumsum(x)[-(n+1)] / sum(x)
})

par(mfrow=c(1,3))
hist(sim.1, main="Algorithm 1")
hist(sim.2, main="Algorithm 2")
hist(sim.3, main="Exponential")

Bạn nghĩ gì về thuật toán (dựa trên thống kê thứ tự xếp hạng) trong câu trả lời của tôi? ;-)
Có QUIT - Anony-Mousse

@Anony Đây là phiên bản kém hiệu quả hơn trong thuật toán của tôi 3. (Bản thân bạn dường như liên quan đến việc thay đổi kích thước không cần thiết.) Bạn tạo ra các biến thiên theo cấp số nhân bằng cách lấy nhật ký của đồng phục, là tiêu chuẩn.
whuber

6

Thuật toán đầu tiên tạo ra các số cách đều nhau

Xem thêm loạt sai lệch thấp .

[0;1]

(Như đã chỉ ra, điều này có thể là một mong muốn ví dụ như tài sản để phân tầng. Loạt thấp nhất quán như Halton và Sobel làm có trường hợp sử dụng của họ.)

Một cách tiếp cận phù hợp nhưng đắt tiền (cho các giá trị thực)

... là sử dụng các số ngẫu nhiên phân phối beta. Thống kê thứ tự xếp hạng của phân phối thống nhất là phân phối beta. Bạn có thể sử dụng điều này để vẽ ngẫu nhiên nhỏ nhất , sau đó nhỏ nhất thứ hai, ... lặp lại.

[0;1]Beta[1,n]n1XBeta[n,1]ln(1X)Exponential[n]. Chúng tôi có thể lấy mẫu các số ngẫu nhiên từ phân phối này là cho việc này.ln(U[0;1])n

ln(1x)=ln(1u)n1x=u1nx=1u1n

Which yields the following algorithm:

x = a
for i in range(n, 0, -1):
    x += (b-x) * (1 - pow(rand(), 1. / i))
    result.append(x) 

There may be numerical instabilities involved, and computing pow and a division for every object may turn out to be slower than sorting.

For integer values you may need to use a different distribution.

Sorting is incredibly cheap, so just use it

But don't bother. Sorting is so ridiculously cheap, so just sort. Over the years, we have well understood how to implement sorting algorithms that sorting doubles is not worth avoiding. Theoretically it's O(nlogn) but the constant term is so ridiculously small in a good implementation that this is the perfect example how useless theoretical complexity results can be. Run a benchmark. Generate 1 million randoms with and without sorting. Run it a few times, and I wouldn't be surprised if quite often the sorting beats the non-sorting, because the cost of sorting will still be much less than your measurement error.


1
There can be reasons to avoid sorting. One is when you want to generate a huge number of random variates, so many that a standard sort routine cannot handle them.
whuber

I think the numerical issues with sums using floating point math become a problem much earlier. (And the problems with cyclic patterns in pseudo random numbers!) It's fairly easy to scale the sorting approach to terabytes, and to exabytes on distributed systems.
Has QUIT--Anony-Mousse

With scaling that large, the log term starts becoming more ... interesting. Although it's good to be concerned about floating point errors, they are not going to be of any consequence until you are summing more than about 1012 values and the problem is easily solved (albeit by more programming, I admit) by breaking the sums into subgroups. My point is that when you are performing a calculation that needs to step in sequence through a set of uniform variates, the non-sorting methods completely avoid having to generate, store, and sort all of them initially.
whuber

Ok, not having to store them is an argument. But then you'll need my approach, your variant 3 using the cumulative sum won't work.
Has QUIT--Anony-Mousse

That is an excellent point. Now I see the virtue of the extra calculations! (+1)
whuber

5

It also depends on what you are doing with the random numbers. For numerical integration problems method one(when corrected by removing the floor operator) would produce superior point set. What you are doing is a form of stratified sampling and it has the advantage that it avoids clumping. it's impossible to get all your values in 0-(b-a)/n range for example. That said for other applications this could be very bad, it depends on what you want to do with it.


2
+1 I think this is a useful contribution to the question, especially by characterizing Algorithm 1 in terms of stratification.
whuber
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.