【问题标题】:loop over dataframe to simulate normal data distrbution循环数据帧以模拟正常的数据分布
【发布时间】:2021-08-27 13:39:30
【问题描述】:

我想循环一个包含数据模拟参数的数据帧。理想情况下,我可以避免为此编写 for loop 并在 tidyverse 中进行,但我还没有找到可行的解决方案。

考虑一个带参数的数据框:

grouping1 <- c('a','a', 'a', 'b', 'b', 'b')
grouping2 <- c('A','A', 'B', 'B', 'C', 'C')
grouping3 <- c('1','2', '3', '4', '5', '6')
observations <- c(14, 14, 12, 12, 15, 15)
average <- c(334, 336, 243, 645, 233, 625)
variance <- c(2, 6, 7, 9, 2, 6)
my_data <- cbind(grouping1,grouping2,grouping3,observations,average,variance)

还有一个简单的管道来根据这些参数模拟值:

my_generated_data <- my_data %>%
  group_by(grouping1,grouping2,grouping3) %>%
  rnorm(n=observations, mean=average, sd=variance) 

但这不起作用。一方面,我收到关于未使用的“。”的错误。论点,但以下也不起作用:

my_generated_data <- my_data %>%
  group_by(grouping1,grouping2,grouping3) %>%
  rnorm(n=.$observations, mean=.$average, sd=.$variance) 

另一个问题是生成的观察数量因分组级别(例如 12、14 或 15)而异。这不应该是一个主要问题,但这确实意味着生成的数据帧必须很长,而不是很宽,因为行数不均匀。提前感谢您的帮助。

【问题讨论】:

    标签: r dplyr simulation


    【解决方案1】:

    Joans 已经回答了这个问题,但我想使用tidyverse 添加解决方案。

    首先,使用 R >= 4.0,您在定义 data.frames 时不需要stringsAsFactors 参数。 my_data的定义很简单

    my_data <- data.frame(grouping1,grouping2,grouping3,observations,average,variance)
    

    现在我们可以使用

    library(dplyr)
    
    my_generated_data <- my_data %>% 
      group_by(grouping1, grouping2, grouping3) %>% 
      mutate(sim = list(rnorm(n = observations, mean = average, sd = sqrt(variance))))
    

    得到

    # Groups:   grouping1, grouping2, grouping3 [6]
      grouping1 grouping2 grouping3 observations average variance sim       
      <chr>     <chr>     <chr>            <dbl>   <dbl>    <dbl> <list>    
    1 a         A         1                   14     334        2 <dbl [14]>
    2 a         A         2                   14     336        6 <dbl [14]>
    3 a         B         3                   12     243        7 <dbl [12]>
    4 b         B         4                   12     645        9 <dbl [12]>
    5 b         C         5                   15     233        2 <dbl [15]>
    6 b         C         6                   15     625        6 <dbl [15]>
    

    其中sim 列包含基于同一行中的observationsaveragevariance 的模拟数据列表。您现在可以使用例如提取此列表

    my_generated_list[[1, "sim]]
    #> [[1]]
    #> [1] 333.9635 335.0959 334.2201 335.6582 335.0773 335.6701 331.9570 334.0041 332.9627 333.5582 335.6228 334.4168 330.4192
    #> [14] 335.2726
    

    unnest

    my_data %>% 
      group_by(grouping1, grouping2, grouping3) %>% 
      mutate(sim = list(rnorm(n = observations, mean = average, sd = sqrt(variance)))) %>% 
      unnest_wider(sim) # use unnest(sim) or unnest_longer(sim) for a "long" format
    

    返回

    # A tibble: 6 x 21
    # Groups:   grouping1, grouping2, grouping3 [6]
      grouping1 grouping2 grouping3 observations average variance  ...1  ...2  ...3  ...4  ...5  ...6  ...7  ...8  ...9 ...10
      <chr>     <chr>     <chr>            <dbl>   <dbl>    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    1 a         A         1                   14     334        2  334.  333.  337.  335.  332.  334.  335.  334.  335.  333.
    2 a         A         2                   14     336        6  338.  336.  333.  334.  334.  336.  333.  339.  336.  335.
    3 a         B         3                   12     243        7  243.  244.  243.  241.  241.  250.  243.  239.  243.  240.
    4 b         B         4                   12     645        9  645.  645.  647.  641.  648.  639.  650.  647.  643.  641.
    5 b         C         5                   15     233        2  232.  234.  235.  237.  233.  232.  235.  231.  233.  236.
    6 b         C         6                   15     625        6  621.  625.  632.  625.  626.  626.  623.  620.  627.  630.
    # ... with 5 more variables: ...11 <dbl>, ...12 <dbl>, ...13 <dbl>, ...14 <dbl>, ...15 <dbl>
    

    【讨论】:

    • 太好了,谢谢!我很欣赏 tidyverse 的解释。
    【解决方案2】:

    第一个问题是将向量组合成一个矩阵。结果矩阵的类型是character,因为至少一个向量是character。您需要存储保持其类型的向量的类型是data.frame,例如

    my_data <- data.frame(grouping1 = grouping1,
                          grouping2 = grouping2,
                          grouping3 = grouping3,
                          observations = observations,
                          average = average,
                          variance = variance, 
                          stringsAsFactors = FALSE)
    

    现在,您可以遍历数据框的行并模拟您的数据。由于模拟的长度取决于您提到的observation-列,因此创建一个观察列表:

    simulationList <- lapply(1:NROW(my_data), function(k) {
      rnorm(n = my_data$observations[k], mean = my_data$average[k], sd = sqrt(my_data$variance[k])) 
    })
    

    您现在想要将模拟添加到您的数据框中。这是否是一个好主意,是你的一部分。但是您可以通过将数据框扩展(复制)到合适的长度并添加模拟来实现这一点

    my_data <- my_data[rep(1:NROW(my_data), times = my_data$observations),]
    my_data$simulation <- unlist(simulationList)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 2021-04-16
      • 1970-01-01
      • 1970-01-01
      • 2022-12-20
      • 1970-01-01
      相关资源
      最近更新 更多