簡體   English   中英

生成具有標准偏差的特定范圍內的隨機數?

[英]Generate random numbers in a specific range with a standard deviation?

我已經知道如何在一個范圍內生成隨機數。 我可以通過使用來做到這一點

rand.nextInt((max - min) + 1) + min;

問題是我還想為這些數字設置標准偏差。 數字也需要是正數,它們不在0和1之間

編輯我刪除了ThreadLocalRandom類,因為我無法在該類中設置種子,這些隨機數應該可以在不同的系統中重現。

選擇有界分布的標准偏差(或方差)只能在取決於所選分布和區間邊界(min, max)的約束條件下進行。 某些分布可能允許您使方差任意小(例如Beta分布 ),其他分布(如統一分布 )在設置邊界(min, max)不允許任何靈活性。 在任何情況下,你永遠無法使方差任意大 - 邊界確實阻止了這一點(它們總是輸入分布的方差的表達式)。

我將通過一個非常簡單的示例來說明這一點,該示例可以在不需要任何第三方庫的情況下實現。 假設您想要在區間(min, max)上進行對稱分布,對稱性意味着分布的平均E(X)位於區間的中間: E(X) = (min + max)/2

x = a + (b - a) * rnd.nextDouble()使用Random的nextDouble將在區間a <= x < b中為您提供均勻分布的隨機變量,該區間具有固定的方差Var(X) = (b - a)^2 / 12 (不是我們想要的)。

OTH,在相同的區間(a, b)上模擬對稱的三角形分布將給出一個隨機變量,它具有相同的均值,但只有一半的方差: Var(X) = (b - a)^2 / 24 (也是固定的) ,所以也不是我們想要的)。

具有參數(a < b < c < d)的對稱梯形分布位於區間(a, d)上的均勻中間和三角形分布的某處。 對稱條件意味着d - c = b - a ,在下文中我將指代距離b - a作為x或“位移”(我已經構成了該名稱,它不是技術術語)。

如果讓x從上方接近0.0,則梯形將看起來非常類似於均勻分布,並且其方差將傾向於最大可能值(d - a)^2 / 12 如果讓x接近下面的最大可能值(d - a)/2 ,則梯形看起來非常類似於對稱三角形分布,其方差將接近(d - a)^2 / 24) 2/24的最小可能值。 (但請注意,為了不破壞方差公式或梯形算法,我們應遠離這些極值。

所以,我們的想法是構造一個帶有x值的梯形分布,它產生你想要的標准偏差,條件是你的目標標准偏差必須位於(0.2041(d - a), 0.2886(d - a))給出的開放范圍內(大致(0.2041(d - a), 0.2886(d - a)) 為方便起見,我們假設a = min = 2.0d = max = 10.0 ,它給出了這個可能的stddevs范圍: (1.6328, 2.3088) 讓我們進一步假設我們想構建一個stddev為2.0的分布(當然,它必須在允許的范圍內)。

解決這個問題需要3個步驟:

1)我們需要有一個給定min, max和位移x的允許值的方差的公式

2)我們需要以某種方式“反轉”這個表達式,為我們的目標方差提供x的值

3)一旦我們知道x的值,我們必須構造一個具有對稱梯形分布的隨機變量,其參數(min, max, x)

第1步

/**
 * Variance of a symmetric trapezoidal distribution with parameters
 * {@code a < b < c < d} and the length of {@code d - c = b - a}
 * (by symmetry) identified by {@code x}.
 * 
 * @param a support lower bound
 * @param d support upper bound
 * @param x length of {@code d - c = b - a}, constrained to lie in the open
 *          interval {@code (0, (d-a)/2)}
 * @return variance of the symmetric trapezoidal distribution defined by
 *         the triple {@code (a, d, x)}
 */
static double varSymTrapezoid(double a, double d, double x) {
    if (a <= 0.0 || d <= 0.0 || a >= d) {
        throw new IllegalArgumentException();
    }
    if (x <= 0.0 || x >= (d - a) / 2) {
        throw new IllegalArgumentException();
    }
    double b = a + x;
    double c = d - x;
    double b3 = pow(b, 3);
    double c3 = pow(c, 3);
    double ex2p1 = pow(b, 4) / 4 - a * b3 / 3 + pow(a, 4) / 12;
    double ex2p2 = (c3 / 3 - b3 / 3) * (d - c);
    double ex2p3 = pow(c, 4) / 4 - d * c3 / 3 + pow(d, 4) / 12;
    double ex2 = (ex2p1 + ex2p2 + ex2p3) / ((d - b) * (d - c));
    return ex2 - pow((a + d) / 2, 2);
}

請注意,此公式僅對對稱梯形分布有效。 舉個例子,如果你用2.5的位移( varSymTrapezoid(2.0, 10.0, 2.5) )來調用這個方法,它會給你一個大約3.0416的方差,這個方差太低了(我們需要4.0),這意味着2.5太多(更高的位移給出更低的方差)。

方差表達式是x中的四階多項式,我不想分析求解。 但是,對於允許范圍內的目標x ,此表達式是單調遞減的,因此我們可以為目標方差構造一個過零的函數,並通過簡單的二分法求解。 這是

第2步

/**
 * Find the displacement {@code x} for the given {@code stddev} by simple
 * bisection.
 * @param min support lower bound
 * @param max support upper bound
 * @param stddev the standard deviation we want
 * @return the length {@code x} of {@code d - c = b - a} that yields a
 * standard deviation roughly equal to {@code stddev}
 */
static double bisect(double min, double max, double stddev) {
    final double eps = 1e-4;
    final double var = pow(stddev, 2);
    int iters = 0;
    double a = eps;
    double b = (max - min) / 2 - eps;
    double x = eps;
    double dx = b - a;

    while (abs(dx) > eps && iters < 150 && eval(min, max, x, var) != 0.0) {
        x = ((a + b) / 2);
        if ((eval(min, max, a, var) * eval(min, max, x, var)) < 0.0) {
            b = x;
            dx = b - a;
        } else {
            a = x;
            dx = b - a;
        }
        iters++;
    }
    if (abs(eval(min, max, x, var)) > eps) {
        throw new RuntimeException("failed to find solution");
    }
    return x;
}

/**
 * Function whose root we want to find.
 */
static double eval(double min, double max, double x, double var) {
    return varSymTrapezoid(min, max, x) - var;
}

bisect方法調用標准偏差的期望值2.0( bisect(2.0, 10.0, 2.0) )給出了所需的位移: ~ 1.1716 現在x的值已知,我們要做的最后一件事就是構造一個適當分布的隨機變量

第3步

概率論的一個眾所周知的事實是,兩個獨立的均勻分布隨機變量X1 ~ U[a1, b1]X2 ~ U[a2, b2]是區間[a1 + X2 ~ U[a2, b2]上的對稱梯形分布隨機變量。 a2,b1 + b2]提供a1 + b2 < a2 + b1 (情況1)或a2 + b1 < a1 + b2 (情況2)。 我們必須避免情況a2 + b1 = a1 + b2 (情況3),因為總和具有我們不想要的對稱三角形分布。

我們將選擇案例1( a1 + b2 < a2 + b1 )。 在那種情況下, b2 - a2的長度將等於“位移” x

因此,我們所要做的就是選擇區間邊界a1,a2,b1和b2,使得a1 + a2 = minb1 + b2 = maxb2 - a2 = x ,並且上面的不等式是滿的:

/**
 * Return a pseudorandom double for the symmetric trapezoidal distribution
 * defined by the triple {@code (min, max, x)}
 * @param min support lower bound
 * @param max support upper bound
 * @param x length of {@code max - c = b - min}, constrained to lie in the
 *          open interval {@code (0, (max-min)/2)}
 */
public static double symTrapezoidRandom(double min, double max, double x) {
    final double a1 = 0.5 * min;
    final double a2 = a1;

    final double b1 = max - a2 - x;
    final double b2 = a2 + x;

    if ((a1 + b2) >= (a2 + b1)) {
        throw new IllegalArgumentException();
    }

    double u = a1 + (b1 - a1) * rnd.nextDouble();
    double v = a2 + (b2 - a2) * rnd.nextDouble();
    return u + v;
}

重復調用symTrapezoidRandom(2.0, 10.0, 1.1716)會為您提供具有所需分布的隨機變量。

您可以使用其他更復雜的發行版(Beta版)執行非常類似的操作。 這將為您提供允許差異的其他(通常更靈活)界限,但您需要第三方庫,如commons.math

abspowsqrt在代碼中引用了靜態導入的java.lang.Math方法,而rnd是java.util.Random的一個實例。

暫無
暫無

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

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