【问题标题】:Sample random rows in dataframe with probability以概率对数据框中的随机行进行采样
【发布时间】:2017-09-22 08:06:35
【问题描述】:

如何在给定概率的情况下随机抽取样本(有或没有替换)?

我正在尝试在 iris 数据框中提取随机行样本,但具有以下物种条件: 80% 杂色和 20% 维吉尼亚

> head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa 

【问题讨论】:

标签: r random dataframe


【解决方案1】:

你可以在 base R 中试试这个:

f.sample <- function(a, percent) a[sample(nrow(a), nrow(a)*percent, replace = TRUE),]

f.sample(iris[iris$Species=="versicolor",], 0.8)
f.sample(iris[iris$Species=="virginica",], 0.2)

您可以相应地设置replace 参数。

【讨论】:

  • 不错的一个。打算写它;-)只是对OP的警告。在生成的数据框中,Species 仍然是一个具有 3 个级别的因子,尽管您只考虑 2 个(杂色和弗吉尼亚)。要删除未使用的因子(如果需要),您可以使用 droplevels(df) 假设 df 是过滤后的结果数据框。
  • 他们想要随机抽取 80% 杂色和 20% 维吉尼亚的样本。您的方法意味着组大小必须相等,因为您只对所有组条目的 X% 进行采样。虽然这对于 iris 数据集是正确的,但在现实世界的数据集中通常不是这样
  • @docendodiscimus 不管底层数据集如何,如果我们想要特定组的x%,为什么它不正确?我想看看我错过了什么。
  • 如果我正确理解了 OP,他们想要一个原始数据的随机样本,其中 80% 的新数据集的行是“杂色”,20% 是“virginica”。例如,假设初始数据集有 50% 杂色、10% 维吉尼亚和其他物种。
  • @docendodiscimus 啊哈,谢谢。那是另一个观点。但鉴于问题的定义(即,对于iris 数据框),它是正确的。
【解决方案2】:

我的理解似乎与其他回答者不同。

无论原始数据集中的组大小如何,以下函数都应生成 80/20 数据集。

foo <- function(DF, n = 50, group_var, groups, probs, replace = FALSE) {

  # subset relevant groups & split
  DF <- DF[DF[[group_var]] %in% groups, ]
  DF <- split(DF, as.character(DF[[group_var]]))
  DF <- DF[match(names(DF), groups)]

  # sample number of observations per group (this requires replace= TRUE)
  smpl <- sample(groups, size = n, replace = TRUE, prob = probs)
  # subset random rows per group according to group size
  DF <- Map(function(x,y) x[sample(1:nrow(x), y, replace = replace),], DF, c(table(smpl)))

  # combine and clean up
  DF <- do.call(rbind, DF)
  DF <- DF[sample(nrow(DF)),]  # not really necessary  
  row.names(DF) <- NULL        # not really necessary  
  DF
}


foo(iris, 50, "Species", c("versicolor", "virginica"), c(0.8, 0.2))

【讨论】:

    【解决方案3】:

    我们可以利用dplyr(即将发布0.6.0)开发版中的quosures来创建函数

    library(tidyverse)
    f.sample <- function(dat, colN, value, perc){
           colN <- enquo(colN)
           value <- quo_name(enquo(value))
           dat %>%
                filter(UQ(colN) == UQ(value)) %>%
                sample_frac(perc) %>%
                droplevels
    }
    
    f.sample(iris, Species, versicolor, 0.8)
    f.sample(iris, Species, virginica, 0.2)
    #Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    #20          6.0         2.2          5.0         1.5 virginica
    #9           6.7         2.5          5.8         1.8 virginica
    #15          5.8         2.8          5.1         2.4 virginica
    #10          7.2         3.6          6.1         2.5 virginica
    #12          6.4         2.7          5.3         1.9 virginica
    #49          6.2         3.4          5.4         2.3 virginica
    #22          5.6         2.8          4.9         2.0 virginica
    #34          6.3         2.8          5.1         1.5 virginica
    #2           5.8         2.7          5.1         1.9 virginica
    #44          6.8         3.2          5.9         2.3 virginica
    

    enquo 具有与substitute 类似的功能,方法是获取输入参数并将其转换为quosure,而quo_name 转换为字符串,并且在filter/group_by/summarise/mutate 内,通过取消引用来评估quosures (@987654330 @或UQ)


    基于下面的 cmets,我们修改了函数,使其适用于其他情况

    f.sample2 <- function(dat, colN, values, perc){
              colN <- enquo(colN)
              dat %>%
                  filter(UQ(colN) %in% values) %>%
                  droplevels %>%
                  nest(-UQ(colN)) %>%
                  .$data %>%
                  setNames(values) %>%
                  Map(sample_frac, ., perc) %>%
                  bind_rows(.id = quo_name(colN))               
    
            } 
    
    
    res <- f.sample2(iris, Species, c("versicolor", "virginica"), c(0.8, 0.2))
    prop.table(table(res$Species))
    #versicolor  virginica 
    #      0.8        0.2 
    

    【讨论】:

    • 他们想随机抽取 80% 杂色和 20% 维吉尼亚的样品。您的方法意味着组大小必须相等,因为您只对所有组条目的 X% 进行抽样。虽然这对于 iris 数据集是正确的,但在现实世界的数据集中通常不是这样。
    • @docendodiscimus 我发布了一个新功能。符合你的条件吗?谢谢。我试图用map2map 替换Map,但它不能正常工作。你有什么建议吗?谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多