【问题标题】:Simulations by row in RR中的逐行模拟
【发布时间】:2019-04-24 22:20:45
【问题描述】:

我正在尝试在模拟中使用分位数来获得 90% 的间隔。我有一个数据集,其中每一行都包含一个平均值、标准差和要运行的模拟次数。

当我尝试运行代码时,出于某种原因,它只会为整个数据集创建分位数,而不是使用每行中包含的信息作为模拟参数。有什么方法可以让它对每一行都有效吗?

这是我正在使用的示例:

avg <- c(24, 20, 29, 17, 22, 21)
sd <- c(5, 4, 5, 3, 3, 3.6)
sims <- 1000
df <- data.frame(avg, sd, sims)

df$Low90 <- round(quantile(rnorm(n = sims, mean = df$avg, sd = df$sd), prob = 0.05), 2)
df$High90 <- round(quantile(rnorm(n = sims, mean = df$avg, sd = df$sd), prob = 0.95), 2)

df
  avg  sd sims Low90 High90
1  24 5.0 1000 14.13  32.32
2  20 4.0 1000 14.13  32.32
3  29 5.0 1000 14.13  32.32
4  17 3.0 1000 14.13  32.32
5  22 3.0 1000 14.13  32.32
6  21 3.6 1000 14.13  32.32

【问题讨论】:

    标签: r simulation


    【解决方案1】:

    这是一个使用pmaptidyverse 方法,因此您只需针对任意数量的分位数对行进行一次迭代。您原始方法中的问题是 rnorm 没有通过其 n 参数进行矢量化;尝试运行 rnorm(n = sims, mean = df$avg, sd = df$sd) 并注意你只得到一组 1000 个值。

    在这里,我们将使用pmap 来遍历行,应用一个自定义函数,该函数采用与probs 参数一样多的分位数。我们需要使用enframespread 来使这些分位数而不是数字向量变为小数,以便unnest 将所有内容保持在同一行。好处是,现在如果您想要,例如,每个百分位数,您只需更改 probs 向量并获得 100 个新列。

    avg <- c(24, 20, 29, 17, 22, 21)
    sd <- c(5, 4, 5, 3, 3, 3.6)
    sims <- 1000
    df <- data.frame(avg, sd, sims)
    
    library(tidyverse)
    probs <- c(0.05, 0.5, 0.95)
    quantile_tbl <- function(sims, avg, sd, probs) {
      rnorm(sims, avg, sd) %>%
        quantile(probs) %>%
        round(2) %>%
        enframe() %>%
        spread(name, value)
    }
    df %>%
      mutate(quantiles = pmap(select(., sims, avg, sd), ~quantile_tbl(..1, ..2, ..3, probs))) %>%
      unnest()
    #>   avg  sd sims    5%   50%   95%
    #> 1  24 5.0 1000 15.96 24.04 32.42
    #> 2  20 4.0 1000 13.53 20.17 26.72
    #> 3  29 5.0 1000 20.59 29.13 37.27
    #> 4  17 3.0 1000 11.83 17.08 21.76
    #> 5  22 3.0 1000 16.75 22.05 27.17
    #> 6  21 3.6 1000 14.87 20.79 26.94
    

    reprex package (v0.2.1) 于 2019 年 4 月 24 日创建

    【讨论】:

    • 您能解释一下这种方法的优点吗?我的基准测试可能是错误的,但似乎很慢?
    • 尚未进行基准测试,enframespread 的开销更大,但无论列数如何,都只有一次迭代。对于任何内存数据集,无论如何它都应该非常快。主要优点是,如果要制作两个以上的分位数列,则不需要每列换行,这使其更具可读性。如果您需要 100 个分位数,只需更改为 probs &lt;- seq(0.01, 0.99, 0.01)
    • 我明白了,仅使用 2 个百分位数时似乎慢了 5 倍,但我想如果你想要 10,20 等......这种方法效率更高。谢谢:)
    【解决方案2】:

    使用apply

    df$Low90 <- apply(df, 1, function(x) round(quantile(rnorm(n = x[3], mean = x[1], sd = x[2]), prob = 0.05), 2))
    df$High90 <- apply(df, 1, function(x) round(quantile(rnorm(n = x[3], mean = x[1], sd = x[2]), prob = 0.95), 2))
    df
    
     avg  sd sims Low90  High90
    1  24 5.0 1000 16.08 32.08
    2  20 4.0 1000 13.65 26.78
    3  29 5.0 1000 20.55 36.96
    4  17 3.0 1000 11.94 22.26
    5  22 3.0 1000 17.13 26.95
    6  21 3.6 1000 14.79 26.84
    

    我们正在做的是使用 apply 函数,边距为 1,这意味着逐行。然后在每一行中,我们得到meanssdsimulation 数字,并通过你的模拟函数运行它。

    dplyr 解决方案将使用 rowwise 函数,

    library(dplyr)
    df %>% rowwise %>% 
      mutate(Low90 = round(quantile(rnorm(n = sims, mean = avg, sd = sd), prob = 0.05), 2))
    

    【讨论】:

      猜你喜欢
      • 2018-10-27
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      • 1970-01-01
      • 2021-06-04
      • 1970-01-01
      相关资源
      最近更新 更多