假设它们都均匀分布,如何从上下边界模拟R中的值?

问题描述

我有以下提示

# A tibble: 1,100 x 3
   income       minimum       maximum
    <dbl>         <dbl>         <dbl>
 1     NA            NA            NA
 2      0             0            25
 3      0             0            25
 4     NA            NA            NA
 5      4           100           200

我想在最小值和最大值遵循均匀分布的假设下模拟一个值。

任何想法该怎么做? 模拟值应显示在可变收入下方的右侧。

解决方法

这可能是您要寻找的:

df$salary <- runif(nrow(df)) * (df$upperboundary - df$lowerboundary) + df$lowerboundary

runif的默认间隔是0-1。通过此操作,您可以将其转换为边界。这是最快的解决方案。

如果您的代码是整洁的,请使用dplyr

df %>% mutate(salary = runif(n()) * (upperboundary - lowerboundary) + lowerboundary)

但是,也可以直接定义边界:

df$salary <- runif(nrow(df),df$lowerboundary,df$upperboundary)

如果您没有NA,那么这将是最佳且最快的解决方案。 无论如何,它是最易读的。 [感谢@ user20650的帮助!]


其他详细信息。

这是如何工作的?

runif(nrow(df)) * (df$upperboundary - df$lowerboundary) + df$lowerboundary

让我们看一下1,让我们手动定义一个最大值和一个最小值。

默认情况下,runif(1)等于:

runif(1,min = 0,max = 1)

因此,它根据均匀分布返回0到1之间的随机数。

要返回两个不同限制之间的随机数,例如min = 10max = 20,您可以这样操作:

runif(1,min = 10,max = 20)

min <- 10
max <- 20
runif(1,max = 1) * (max - min) + min

如果runif的输出为0:

0 * (20 - 10) + 10
==> 10

如果runif的输出为1:

1 * (20 - 10) + 10
==> 20 - 10 + 10
==> 20

这里还有dplyr的替代方案,而apply的解决方案是

library(dplyr)
df %>% 
  rowwise() %>% 
  mutate(salary = runif(1,lowerboundary,upperboundary)) %>% 
  ungroup()

这里是速度比较。 “数学”是最快的:

microbenchmark::microbenchmark(
  apply  =  apply(df[-1],1,function(x) runif(1,x[1],x[2])),maths  =  runif(nrow(df)) * (df$upperboundary - df$lowerboundary) + df$lowerboundary,maths2 =  runif(nrow(df),df$upperboundary),dplyr  =  df %>% rowwise() %>% mutate(runif = runif(1,upperboundary)) %>% ungroup()
)
#> Unit: microseconds
#>    expr    min      lq     mean  median      uq    max neval
#>   apply  907.1  955.90 1175.188 1023.70 1280.90 4455.0   100
#>   maths   16.8   26.05   32.651   31.25   38.65   75.0   100
#>  maths2  117.8  128.00  156.533  136.60  175.15  336.7   100
#>   dplyr 1424.2 1496.60 1821.068 1661.15 1989.20 3952.7   100
,

尝试使用apply()的此方法。您可以在行级使用runif()lowerboundary变量来使用upperboundary生成值。对于带有NA的行,您将获得NaN。这里的代码:

#Code
df$Salary <- apply(df[,-1],function(x) {y <- runif(1,x[2]); y})

输出:

   income lowerboundary upperboundary     Salary
1      NA            NA            NA        NaN
2       0             0            50   26.86049
3       0             0            50   36.44212
4      NA            NA            NA        NaN
5       4           425           600  459.25802
6      NA            NA            NA        NaN
7      NA            NA            NA        NaN
8       4           425           600  535.39891
9      NA            NA            NA        NaN
10     12          2400          3000 2754.34136

使用了一些数据:

#Data
df <- structure(list(income = c(NA,0L,NA,4L,12L),lowerboundary = c(NA,425L,2400L),upperboundary = c(NA,50L,600L,3000L)),row.names = c(NA,-10L),class = "data.frame")
,

我们可以使用map2中的purrr

library(purrr)
library(dplyr)
df %>%
   mutate(salary = map2_dbl(lowerboundary,upperboundary,~ runif(1,.x,.y)))

-输出

#   income lowerboundary upperboundary      salary
#1      NA            NA            NA         NaN
#2       0             0            50   33.771312
#3       0             0            50    3.577857
#4      NA            NA            NA         NaN
#5       4           425           600  514.912989
#6      NA            NA            NA         NaN
#7      NA            NA            NA         NaN
#8       4           425           600  516.179313
#9      NA            NA            NA         NaN
#10     12          2400          3000 2815.442543