R生成有界随机样本周围特定均值
R Generate Bounded Random Sample Arround Specific Mean
我被这个问题困扰了一段时间,所以我决定写一个问题。
问题:如何生成具有lower/upper的随机样本(长度为n)并围绕特定的平均值.
观察:分布不需要特定(可以是正态、beta 等)。
考虑的方法:
- 一种方法是使用
rtnorm
函数 (package msm) 生成一个在指定范围内呈正态分布的随机数,但它不包含您想要的平均值。
我尝试过的第二个方法是这个函数,我在一个我找不到的问题中找到了它
rBootstrap <- function(n, mean, sd, lowerBound, upperBound){
range <- upperBound - lowerBound
m <- (mean-lowerBound) / range #mapping mean to 0-1 range
s <- sd / range #mapping sd to 0-1 range
a <- (m^2 - m^3 - m*s^2)/s^2 #calculating alpha for rbeta
b <- (m-2*m^2+m^3-s^2+m*s^2)/s^2 #calculating beta for rbeta
data <- rbeta(n,a,b) #generating data
data <- lowerBound + data * range #remaping to given bounds
return(data)
}
这个函数实际上给出了很好的结果,除非:upperBound > lowerBound + (2* mean - lowerBound)(上限超过从 lowerBound 到均值的距离的两倍)。
特别是,我想生成一个长度为 1,800 的随机样本,其值介于 50,000 和 250,000 之间,平均值 = 70,000。
您应该使用截断正态分布,但 mean
应该重新校准。如果你看一下rtnorm
中的mean
,很明显:mean
是截断前原始正态分布的均值。
如果您希望 OBSERVABLE 的意思等于所需的值,只需使用 Truncated Normal:
中的公式
mu = E + sigma*(f(b) - f(a))/(F(b) - F(a))
这里 E
是你想要的平均值(在你的例子中是 70,000),f(x)
是高斯密度,F(x)
是累积函数,a
和b
是间隔边界(居中和缩放)。
a = (LB - mu)/sigma
b = (RB - mu)/sigma
计算 mu
后,将其作为 mean
参数传递给 rtnorm。
注意:你可能想用 sigma
做类似的练习 - 进入 rtnorm 的不是你要在采样中观察到的,再次参见 wiki 参考资料
更新
好吧,我自己得到了代码,虽然第一次切割是在 Python 中完成的(查看 R)。问题是,对于给定的可观察均值 mu
在 f(a)
、f(b)
、F(a)
和 F(b)
中,这将问题转换为搜索的根非线性方程。但它是可以解决的,请检查code。请注意,它几乎遵循 wiki 符号。
例如对于你的参数和 sigma=12,000,我得到
Found mu = 68430.372119287 for the desired mean 70000.0 and sigma 12000.0
Sampled 100000 truncated gaussians and got observed mean = 70023.15990337673
对于你的参数和 sigma=24,000,我得到了
Found mu = 52275.475000378945 for the desired mean 70000.0 and sigma 24000.0
Sampled 100000 truncated gaussians and got observed mean = 69922.16000288539
所以 mu
非常接近大 sigma
的左边界,这是预期的行为,但观察到的均值接近 70,000,这正是您想要的。
更新二
这是 R 代码,也在 github 回购
require(rootSolve)
require(msm)
phi <- function(z) {
dnorm(z)
}
Phi <- function(z) {
pnorm(z)
}
Mean <- function(mu, sigma, a, b) {
alfa <- (a - mu) / sigma
beta <- (b - mu) / sigma
Z <- Phi(beta) - Phi(alfa)
mu + sigma*(phi(alfa) - phi(beta))/Z
}
f <- function(mu, mean, sigma, a, b) {
mean - Mean(mu, sigma, a, b)
}
a <- 50000.0
b <- 250000.0
mean <- 70000.0
sigma <- 24000.0
# find mu for desired mean
q <- uniroot(f, c(a, b), mean, sigma, a, b)
mu <- q$root
print(sprintf("Found mu = %f for the desired mean %f and sigma %f", mu, mean, sigma))
# sampling test
set.seed(32345)
N = 100000
r <- rtnorm(N, mean=mu, sd=sigma, lower=a, upper=b)
print(sprintf("Sampled %d truncated gaussians and got observed mean = %f", N, mean(r)))
我被这个问题困扰了一段时间,所以我决定写一个问题。
问题:如何生成具有lower/upper的随机样本(长度为n)并围绕特定的平均值.
观察:分布不需要特定(可以是正态、beta 等)。
考虑的方法:
- 一种方法是使用
rtnorm
函数 (package msm) 生成一个在指定范围内呈正态分布的随机数,但它不包含您想要的平均值。 我尝试过的第二个方法是这个函数,我在一个我找不到的问题中找到了它
rBootstrap <- function(n, mean, sd, lowerBound, upperBound){ range <- upperBound - lowerBound m <- (mean-lowerBound) / range #mapping mean to 0-1 range s <- sd / range #mapping sd to 0-1 range a <- (m^2 - m^3 - m*s^2)/s^2 #calculating alpha for rbeta b <- (m-2*m^2+m^3-s^2+m*s^2)/s^2 #calculating beta for rbeta data <- rbeta(n,a,b) #generating data data <- lowerBound + data * range #remaping to given bounds return(data) }
这个函数实际上给出了很好的结果,除非:upperBound > lowerBound + (2* mean - lowerBound)(上限超过从 lowerBound 到均值的距离的两倍)。
特别是,我想生成一个长度为 1,800 的随机样本,其值介于 50,000 和 250,000 之间,平均值 = 70,000。
您应该使用截断正态分布,但 mean
应该重新校准。如果你看一下rtnorm
中的mean
,很明显:mean
是截断前原始正态分布的均值。
如果您希望 OBSERVABLE 的意思等于所需的值,只需使用 Truncated Normal:
中的公式mu = E + sigma*(f(b) - f(a))/(F(b) - F(a))
这里 E
是你想要的平均值(在你的例子中是 70,000),f(x)
是高斯密度,F(x)
是累积函数,a
和b
是间隔边界(居中和缩放)。
a = (LB - mu)/sigma
b = (RB - mu)/sigma
计算 mu
后,将其作为 mean
参数传递给 rtnorm。
注意:你可能想用 sigma
做类似的练习 - 进入 rtnorm 的不是你要在采样中观察到的,再次参见 wiki 参考资料
更新
好吧,我自己得到了代码,虽然第一次切割是在 Python 中完成的(查看 R)。问题是,对于给定的可观察均值 mu
在 f(a)
、f(b)
、F(a)
和 F(b)
中,这将问题转换为搜索的根非线性方程。但它是可以解决的,请检查code。请注意,它几乎遵循 wiki 符号。
例如对于你的参数和 sigma=12,000,我得到
Found mu = 68430.372119287 for the desired mean 70000.0 and sigma 12000.0
Sampled 100000 truncated gaussians and got observed mean = 70023.15990337673
对于你的参数和 sigma=24,000,我得到了
Found mu = 52275.475000378945 for the desired mean 70000.0 and sigma 24000.0
Sampled 100000 truncated gaussians and got observed mean = 69922.16000288539
所以 mu
非常接近大 sigma
的左边界,这是预期的行为,但观察到的均值接近 70,000,这正是您想要的。
更新二
这是 R 代码,也在 github 回购
require(rootSolve)
require(msm)
phi <- function(z) {
dnorm(z)
}
Phi <- function(z) {
pnorm(z)
}
Mean <- function(mu, sigma, a, b) {
alfa <- (a - mu) / sigma
beta <- (b - mu) / sigma
Z <- Phi(beta) - Phi(alfa)
mu + sigma*(phi(alfa) - phi(beta))/Z
}
f <- function(mu, mean, sigma, a, b) {
mean - Mean(mu, sigma, a, b)
}
a <- 50000.0
b <- 250000.0
mean <- 70000.0
sigma <- 24000.0
# find mu for desired mean
q <- uniroot(f, c(a, b), mean, sigma, a, b)
mu <- q$root
print(sprintf("Found mu = %f for the desired mean %f and sigma %f", mu, mean, sigma))
# sampling test
set.seed(32345)
N = 100000
r <- rtnorm(N, mean=mu, sd=sigma, lower=a, upper=b)
print(sprintf("Sampled %d truncated gaussians and got observed mean = %f", N, mean(r)))