在rnorm中设置上限和下限

时间:2022-01-22 13:05:09

I am simulating data using rnorm, but I need to set an upper and lower limit, does anyone know how to do this?

我正在用rnorm模拟数据,但是我需要设置一个上限和下限,有人知道怎么做吗?

code:

代码:

rnorm(n = 10, mean = 39.74, sd = 25.09)

Upper limit needs to be 340, and the lower limit 0

上限为340,下限为0

I am asking this question because I am rewriting an SAS-code into an R-code. I have never used SAS. I am trying to rewrite the following piece of code:

我正在问这个问题,因为我正在把一个SAS-code改写成R-code。我从未使用过SAS。我正在重写下面的代码:

sim_sample(simtot=100000,seed=10004,lbound=0,ubound=340,round_y=0.01,round_m=0.01,round_sd=0.01,n=15,m=39.74,sd=25.11,mk=4)

5 个解决方案

#1


7  

Like this?

像这样的吗?

mysamp <- function(n, m, s, lwr, upr, nnorm) {
  samp <- rnorm(nnorm, m, s)
  samp <- samp[samp >= lwr & samp <= upr]
  if (length(samp) >= n) {
    return(sample(samp, n))
  }  
  stop(simpleError("Not enough values to sample from. Try increasing nnorm."))
}

set.seed(42)
mysamp(n=10, m=39.74, s=25.09, lwr=0, upr=340, nnorm=1000)
#[1] 58.90437 38.72318 19.64453 20.24153 39.41130 12.80199 59.88558 30.88578 19.66092 32.46025

However, the result is not normal distributed and usually won't have the mean and sd you've specified (in particular if the limits are not symmetric around the specified mean).

但是,结果不是正态分布的,并且通常不会有您指定的平均值和sd(特别是当限制不是围绕指定的平均值对称时)。

Edit:

According to your comment it seems you want to translate this SAS function. I am not an SAS user, but this should do more or less the same:

根据您的评论,您似乎想要翻译这个SAS函数。我不是SAS用户,但这应该或多或少做相同的事情:

mysamp <- function(n, m, s, lwr, upr, rounding) {
  samp <- round(rnorm(n, m, s), rounding)
  samp[samp < lwr] <- lwr
  samp[samp > upr] <- upr
  samp
}

set.seed(8)
mysamp(n=10, m=39.74, s=25.09, lwr=0, upr=340, rounding=3)
#[1] 37.618 60.826 28.111 25.920 58.207 37.033 35.467 12.434  0.000 24.857

You may then want to use replicate to run the simulations. Or if you want faster code:

然后,您可能想要使用replication来运行模拟。或者如果你想要更快的代码:

sim <- matrix(mysamp(n=10*10, m=39.74, s=25.09, lwr=0, upr=340, rounding=3), 10)
means <- colMeans(sim)
sds <- apply(sim, 2, sd)

#2


15  

The rtruncnorm() function will return the results you need.

函数的作用是:返回所需要的结果。

  library(truncnorm)
  rtruncnorm(n=10, a=0, b=340, mean=39.4, sd=25.09)

#3


7  

You can make your own truncated normal sampler that doesn't require you to throw out observations quite simply

你可以自己制作一个截断的普通采样器,它不需要你简单地抛出观测结果

rtnorm <- function(n, mean, sd, a = -Inf, b = Inf){
    qnorm(runif(n, pnorm(a, mean, sd), pnorm(b, mean, sd)), mean, sd)
}

#4


1  

This is the function that I wrote to achieve the same purpose. It normalizes the result from the rnorm function and then adjusts it to fit the range.

这是我为达到相同目的而写的函数。它将rnorm函数的结果规范化,然后调整它以适应范围。

NOTE: The standard deviation and mean (if specified) get altered during the normalization process.

注意:在标准化过程中,标准偏差和平均值(如果指定)会发生变化。

#' Creates a random normal distribution within the specified bounds.
#' 
#' WARNING: This function does not preserve the standard deviation or mean.
#' @param n The number of values to be generated
#' @param mean The mean of the distribution
#' @param sd The standard deviation of the distribution
#' @param lower The lower limit of the distribution
#' @param upper The upper limit of the distribution
rtnorm <- function(n, mean=NA, sd=1, lower=-1, upper=1){
  mean = ifelse(is.na(mean)|| mean < lower || mean > upper,
                mean(c(lower, upper)), mean)
  data <- rnorm(n, mean=m, sd=sd) # data

  if (!is.na(lower) && !is.na(upper)){ # adjust data to specified range
    drange <- range(data)           # data range
    irange <- range(lower, upper)   # input range
    data <- (data - drange[1])/(drange[2] - drange[1]) # normalize data (make it 0 to 1)
    data <- (data * (irange[2] - irange[1]))+irange[1] # adjust to specified range
  }
  return(data)
}

#5


0  

Assuming you want exactly 10 numbers and not the subset of them that is >0, <340 (and night not be a normal distribution):

假设你只需要10个数字,而不是>0 <340(夜不是正态分布)的子集:

    aa <- rnorm(n = 10, mean = 39.74, s = 25.09)

    while(any(aa<0 | aa>340)) { aa <- rnorm(n = 10, mean = 39.74, s = 25.09) }

#1


7  

Like this?

像这样的吗?

mysamp <- function(n, m, s, lwr, upr, nnorm) {
  samp <- rnorm(nnorm, m, s)
  samp <- samp[samp >= lwr & samp <= upr]
  if (length(samp) >= n) {
    return(sample(samp, n))
  }  
  stop(simpleError("Not enough values to sample from. Try increasing nnorm."))
}

set.seed(42)
mysamp(n=10, m=39.74, s=25.09, lwr=0, upr=340, nnorm=1000)
#[1] 58.90437 38.72318 19.64453 20.24153 39.41130 12.80199 59.88558 30.88578 19.66092 32.46025

However, the result is not normal distributed and usually won't have the mean and sd you've specified (in particular if the limits are not symmetric around the specified mean).

但是,结果不是正态分布的,并且通常不会有您指定的平均值和sd(特别是当限制不是围绕指定的平均值对称时)。

Edit:

According to your comment it seems you want to translate this SAS function. I am not an SAS user, but this should do more or less the same:

根据您的评论,您似乎想要翻译这个SAS函数。我不是SAS用户,但这应该或多或少做相同的事情:

mysamp <- function(n, m, s, lwr, upr, rounding) {
  samp <- round(rnorm(n, m, s), rounding)
  samp[samp < lwr] <- lwr
  samp[samp > upr] <- upr
  samp
}

set.seed(8)
mysamp(n=10, m=39.74, s=25.09, lwr=0, upr=340, rounding=3)
#[1] 37.618 60.826 28.111 25.920 58.207 37.033 35.467 12.434  0.000 24.857

You may then want to use replicate to run the simulations. Or if you want faster code:

然后,您可能想要使用replication来运行模拟。或者如果你想要更快的代码:

sim <- matrix(mysamp(n=10*10, m=39.74, s=25.09, lwr=0, upr=340, rounding=3), 10)
means <- colMeans(sim)
sds <- apply(sim, 2, sd)

#2


15  

The rtruncnorm() function will return the results you need.

函数的作用是:返回所需要的结果。

  library(truncnorm)
  rtruncnorm(n=10, a=0, b=340, mean=39.4, sd=25.09)

#3


7  

You can make your own truncated normal sampler that doesn't require you to throw out observations quite simply

你可以自己制作一个截断的普通采样器,它不需要你简单地抛出观测结果

rtnorm <- function(n, mean, sd, a = -Inf, b = Inf){
    qnorm(runif(n, pnorm(a, mean, sd), pnorm(b, mean, sd)), mean, sd)
}

#4


1  

This is the function that I wrote to achieve the same purpose. It normalizes the result from the rnorm function and then adjusts it to fit the range.

这是我为达到相同目的而写的函数。它将rnorm函数的结果规范化,然后调整它以适应范围。

NOTE: The standard deviation and mean (if specified) get altered during the normalization process.

注意:在标准化过程中,标准偏差和平均值(如果指定)会发生变化。

#' Creates a random normal distribution within the specified bounds.
#' 
#' WARNING: This function does not preserve the standard deviation or mean.
#' @param n The number of values to be generated
#' @param mean The mean of the distribution
#' @param sd The standard deviation of the distribution
#' @param lower The lower limit of the distribution
#' @param upper The upper limit of the distribution
rtnorm <- function(n, mean=NA, sd=1, lower=-1, upper=1){
  mean = ifelse(is.na(mean)|| mean < lower || mean > upper,
                mean(c(lower, upper)), mean)
  data <- rnorm(n, mean=m, sd=sd) # data

  if (!is.na(lower) && !is.na(upper)){ # adjust data to specified range
    drange <- range(data)           # data range
    irange <- range(lower, upper)   # input range
    data <- (data - drange[1])/(drange[2] - drange[1]) # normalize data (make it 0 to 1)
    data <- (data * (irange[2] - irange[1]))+irange[1] # adjust to specified range
  }
  return(data)
}

#5


0  

Assuming you want exactly 10 numbers and not the subset of them that is >0, <340 (and night not be a normal distribution):

假设你只需要10个数字,而不是>0 <340(夜不是正态分布)的子集:

    aa <- rnorm(n = 10, mean = 39.74, s = 25.09)

    while(any(aa<0 | aa>340)) { aa <- rnorm(n = 10, mean = 39.74, s = 25.09) }