R(和dplyr?)-按组从数据帧中采样,最大样本量为n

R(和dplyr?)-按组从数据帧中采样,最大样本量为n,r,dplyr,subsampling,R,Dplyr,Subsampling,我有一个数据帧,每个组包含多个样本(1-n)。我想对这个数据集进行采样,不进行替换,这样每个组最多有5个样本(1-5个) 这个问题以前一直存在。在这个问题上,我的回答是最令人满意的,并且在过去一直有效。这似乎在过去的一年左右已经打破了 以下是我想做的一个可行的例子: 在mtcars中,按“cyl”分组时有不同的行数 我想创建一个子样本,其中每个气缸组的最大汽车数量为10辆。理论上得出的行数如下所示: table(subsample$cyl) 4 6 8 10 7 10 我天真的尝试是:

我有一个数据帧,每个组包含多个样本(1-n)。我想对这个数据集进行采样,不进行替换,这样每个组最多有5个样本(1-5个)

这个问题以前一直存在。在这个问题上,我的回答是最令人满意的,并且在过去一直有效。这似乎在过去的一年左右已经打破了

以下是我想做的一个可行的例子:

在mtcars中,按“cyl”分组时有不同的行数

我想创建一个子样本,其中每个气缸组的最大汽车数量为10辆。理论上得出的行数如下所示:

table(subsample$cyl)
 4  6  8
10  7 10
我天真的尝试是:

library(dplyr)
subsample <- mtcars %>% group_by(cyl) %>% sample_n(10) %>% ungroup()
该函数在过去一直有效,我刚刚尝试重新运行它,但它不再有效,相反,它会抛出与mtcars示例当前相同的错误:

library(dplyr)
subsample <- mtcars %>% group_by(cyl) %>% sample_vals(10) %>% ungroup()
库(dplyr)
子样本%group\U by(cyl)%%>%sample\U VAL(10)%%>%ungroup()
dplyr中的错误:::样本组(索引[[i]],分形=假,tbl=tbl,大小=大小[i],: 未使用的参数(tbl=tbl) 调用自:FUN(X[[i]],…)

有没有人有更好的方法可以按组采样,不需要更换,每个组的最大大小?我通常不是dplyr的大用户,所以所有来自base R或其他软件包的选项都是受欢迎的

否则,有没有人知道为什么之前的工作已经停止了


感谢大家的时间。

对于一个简单的函数,您可以使用此解决方案,它首先使用样本不足的组进行破坏,然后在最后过滤掉它们:

library(dplyr)
library(tidyr)

size <- 10

subsample <- mtcars %>% 
  group_by(cyl) %>% 
  mutate(group_count = n(), 
         group_count_along = 1:n()) %>% 
  ungroup() %>% 
  complete(cyl, group_count_along) %>% 
  group_by(cyl) %>% 
  filter(group_count_along <= max(group_count, size, na.rm = T)) %>% 
  sample_n(size) %>% 
  ungroup() %>% 
  filter(group_count_along <= group_count)

table(subsample$cyl)
 4  6  8 
10  7 10 
库(dplyr)
图书馆(tidyr)
大小%
变异(组计数=n(),
组计数沿=1:n())%>%
解组()%>%
完成(气缸、组计数)%>%
组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别组别
过滤器(组计数沿%
样本(大小)%>%
解组()%>%

过滤(沿分组计数这里有一个使用
slice
-

samples_per_group <- 10

subsample <- mtcars %>%
  group_by(cyl) %>%
  slice(sample(n(), min(samples_per_group, n()))) %>%
  ungroup()

table(subsample$cyl)

#  4  6  8 
# 10  7 10
每个组的样本数%
切片(样本(n(),最小值(每组样本,n()))%>%
解组()
表(子样本$cyl)
#  4  6  8 
# 10  7 10

函数
sample\u组
已更新,参数
tbl
.env
已删除。从
sample\u vals
函数中删除这些参数,并删除
+1
将恢复函数的功能

require(dplyr)

sample_vals <- function (tbl, size, replace = FALSE, weight = NULL){
    ## assert_that(is.numeric(size), length(size) == 1, size >= 0)
    weight <- substitute(weight)
    index <- attr(tbl, "indices")
    sizes <- sapply(index, function(z) min(length(z), size)) # here's my contribution
    sampled <- lapply(1:length(index),
                      function(i) dplyr:::sample_group(index[[i]],  frac = FALSE, 
                                                       size = sizes[i],
                                                       replace = replace,
                                                       weight = weight))
    idx <- unlist(sampled) ## + 1
    grouped_df(tbl[idx, , drop = FALSE], vars = groups(tbl))
}

samped_data <- mtcars %>% group_by(cyl) %>% sample_vals(size = 10) %>% ungroup()

table(samped_data$cyl)
require(dplyr)
样本(VAL=0)

重量对于基数R也很简单,例如:

do.call(rbind, lapply(split(mtcars, mtcars$cyl), function(x) {
  n <- nrow(x)
  s <- min(n, 10)
  x[sample(seq_len(n), s),]
}))
do.call(rbind,lappy)(拆分(mtcars,mtcars$cyl),函数(x){

n
sample
的默认长度是完整向量,因此您也可以将
slice(sample(min(samples\u per\u group,n()))
sample.int要求指定n,可供选择的样本数。指定n=10时会发生什么情况(作为每个组和n()的样本数的最小值,但实际n=n()哪个大于10?@RyanD感谢…简化了解决方案。@Aarrgh'sMyGame我想我收到了你的问题,并对示例代码进行了更改。让我知道这是否对你有效。谢谢@Shree,我的问题非常复杂。是的,现在编辑更合理。只需注意:此解决方案有效,但也需要tidyr来完成函数“complete”。这是一个非常快速的响应,kath,但我确实觉得添加和删除假数据行很不方便。从第一组到最后一个过滤器,还有很多工作要做。
require(dplyr)

sample_vals <- function (tbl, size, replace = FALSE, weight = NULL){
    ## assert_that(is.numeric(size), length(size) == 1, size >= 0)
    weight <- substitute(weight)
    index <- attr(tbl, "indices")
    sizes <- sapply(index, function(z) min(length(z), size)) # here's my contribution
    sampled <- lapply(1:length(index),
                      function(i) dplyr:::sample_group(index[[i]],  frac = FALSE, 
                                                       size = sizes[i],
                                                       replace = replace,
                                                       weight = weight))
    idx <- unlist(sampled) ## + 1
    grouped_df(tbl[idx, , drop = FALSE], vars = groups(tbl))
}

samped_data <- mtcars %>% group_by(cyl) %>% sample_vals(size = 10) %>% ungroup()

table(samped_data$cyl)
do.call(rbind, lapply(split(mtcars, mtcars$cyl), function(x) {
  n <- nrow(x)
  s <- min(n, 10)
  x[sample(seq_len(n), s),]
}))