在数据框中每个组中随机抽取n行样本

30

从这些问题中 - R数据框中子集的随机行样本 & 在R数据框中抽样随机行 我可以轻松地看到如何从df中随机抽取(选择)'n'行,或者从df中特定级别的因子中随机抽取 'n'行。

以下是一些示例数据:

df <- data.frame(matrix(rnorm(80), nrow=40))
df$color <-  rep(c("blue", "red", "yellow", "pink"), each=10)

df[sample(nrow(df), 3), ] #samples 3 random rows from df, without replacement.

使用 library(kimisc) 从 'pink' 颜色中随机抽取3行数据示例如下:

library(kimisc)
sample.rows(subset(df, color == "pink"), 3)

或编写自定义函数:

sample.df <- function(df, n) df[sample(nrow(df), n), , drop = FALSE]
sample.df(subset(df, color == "pink"), 3)

然而,我想从因子的每个水平中随机选取3(或n)行进行样本。即新的数据框将有12行(蓝色3行,红色3行,黄色3行,粉色3行)。显然可以运行多次此操作,为每个颜色创建新的数据框,然后将它们绑定在一起,但我正在寻找一个更简单的解决方案。


1
这个回答解决了你的问题吗?按组随机抽样 - camille
5个回答

36

dplyr 的 0.3 版本及其之后的版本中,这个功能可以正常使用:

df %>% group_by(color) %>% sample_n(size = 3)

dplyr 的旧版本(版本号 <= 0.2)

我使用 dplyr 来回答这个问题,假设以下代码可以正常工作:

df %.% group_by(color) %.% sample_n(size = 3)

但事实证明,在版本0.2中sample_n.grouped_df的S3方法存在,但没有在NAMESPACE文件中注册,因此它从未分派。取而代之的是,我必须这样做:

df %.% group_by(color) %.% dplyr:::sample_n.grouped_df(size = 3)
Source: local data frame [12 x 3]
Groups: color

            X1         X2  color
8   0.66152710 -0.7767473   blue
1  -0.70293752 -0.2372700   blue
2  -0.46691793 -0.4382669   blue
32 -0.47547565 -1.0179842   pink
31 -0.15254540 -0.6149726   pink
39  0.08135292 -0.2141423   pink
15  0.47721644 -1.5033192    red
16  1.26160230  1.1202527    red
12 -2.18431919  0.2370912    red
24  0.10493757  1.4065835 yellow
21 -0.03950873 -1.1582658 yellow
28 -2.15872261 -1.5499822 yellow

假定这个问题将在未来的更新中被修复。


你正在使用哪个版本的 dplyr? 它是主干吗? - momeara
我尝试了CRAN上的0.2版本,然后从GitHub安装;结果是一样的。 - joran
1
@joran 在 dplyr 0.3 中这个方法非常好用。现在这是我解决上述问题最喜欢的方式。 - jalapic
这个与 sample_frac 配合使用可以很好地保持类别的相对比例。 - Brian Stamper
现在 dplyr 中已经提供了 slice_sample 函数。 - Maël
显示剩余3条评论

7
我会考虑使用我的stratified函数,目前它作为GitHub Gist托管。
获取它的方法如下:
library(devtools)  ## To download "stratified"
source_gist("https://gist.github.com/mrdwab/6424112")

并且可以使用以下方式:

stratified(df, "color", 3)

在分层抽样中,有几个不同的功能非常方便。例如,您还可以“即时”地对样本进行排序。

stratified(df, "color", 3, select = list(color = c("blue", "red")))

为了让您了解这个函数的作用,以下是 stratified 的参数:

  • df:输入的数据框。
  • group:由一个或多个列组成“分层”的字符向量。
  • size:期望的样本大小。
    • 如果 size 是小于 1 的值,则从每个分层中取出相应比例的样本。
    • 如果 size 是单个大于等于 1 的整数,则从每个分层中取出该数量的样本。
    • 如果 size 是一个整数向量,则对于每个分层,取出指定数量的样本。建议使用 命名向量。例如,如果有两个分层,“A” 和 “B”,并且您想从 “A” 中取 5 个样本,从 “B” 中取 10 个样本,则输入 size = c(A = 5, B = 10)
  • select:允许您在抽样过程中对群组进行子集选择。这是一个 list。例如,如果您的 group 变量是 “Group”,其中包含三个分层,“A”、“B” 和 “C”,但您只想从 “A” 和 “C” 中抽样,则可以使用 select = list(Group = c("A", "C"))
  • replace:是否使用放回抽样。

这是一个非常棒的函数 - 非常有用。 - jalapic
不错且有帮助。在某些版本中,source_gist函数存在一个错误,会引发一个错误。我使用了一个解决方法,如下所示:source_gist("https://gist.github.com/mrdwab/6424112", filename = "stratified.R") - soungalo

7
您可以使用ave为具有特定因子水平的每个元素分配一个随机ID。然后,您可以选择在某个范围内的所有随机ID。
rndid <- with(df, ave(X1, color, FUN=function(x) {sample.int(length(x))}))
df[rndid<=3,]

这样做的好处是如果你关心原始行顺序和行名称,可以保留它们。此外,您可以轻松地重复使用 rndid 向量创建不同长度的子集。


这个建议和另一个答案都非常好。我可以确认一下关于上面的代码的两件事吗?1)变量X1。在这里选择df中的哪个变量是否重要?(似乎不是)。2)在不同因子水平的观测数量不同且我想返回每个因子水平的子集超过某些因子水平中存在的总数时,这个解决方案仍然有效。也就是说,如果我要求每种颜色11行,它将返回10行。这可能在我的真实数据中很有用,因为观测/每个因子水平的行数确实会有所变化。 - jalapic
@jalapic 1) 你说得对,第一个参数传递哪个变量并不重要。传递数字向量有助于保持结果为数字。2) 如果你请求10行(rndid<=10),而一个组只有3行,那么该组的所有三行将被返回,不会引入缺失值,也不会进行替换抽样。因此,你可能会得到不平衡的组。 - MrFlick
谢谢。在这种情况下,我不介意不平衡的组,所以这很完美。 - jalapic
@MrFlick,我想满足卡方检验的样本量条件,所以我需要在每组中抽取至少5个案例,使用您的解决方案该如何实现? - Saeed Zhiany

6

这里有一个解决方案。我们将数据框按颜色分组,然后从每个组中随机抽取3行。这将产生一个数据框列表。

df2 <- lapply(split(df, df$color),
   function(subdf) subdf[sample(1:nrow(subdf), 3),]
)

为了获得所需的结果,我们将数据框的列表合并成一个数据框:
do.call('rbind', df2)
##                    X1          X2  color
## blue.3    -1.22677188  1.25648082   blue
## blue.4    -0.54516686 -1.94342967   blue
## blue.1     0.44647071  0.16283326   blue
## pink.40    0.23520296 -0.40411906   pink
## pink.34    0.02033939 -0.32321309   pink
## pink.33   -1.01790533 -1.22618575   pink
## red.16     1.86545895  1.11691250    red
## red.11     1.35748078 -0.36044728    red
## red.13    -0.02425645  0.85335279    red
## yellow.21  1.96728782 -1.81388110 yellow
## yellow.25 -0.48084967  0.07865186 yellow
## yellow.24 -0.07056236 -0.28514125 yellow

如果我想为分组选择不同的样本大小呢? - dondapati
例如,在这里,3 对于每个组都是固定的,但我想为每个组设置不同的值。 - dondapati
蓝色 我需要 2粉色 我需要 1红色 我需要 5,最后对于 黄色 我需要 3 - dondapati
我用c(2,1,5,3)替换了3,但它只考虑了第一个元素即2 - dondapati

0

这里有一种方法,基于基础,允许多个组和带替换的抽样:

n <- 3
resample <- TRUE
index <- 1:nrow(df)
fun <- function(x) sample(x, n, replace = resample)
a <- aggregate(index, by = list(group = df$color), FUN = fun )

df[c(a$x),]

要添加另一个分组,请将其包含在“by”参数中进行聚合。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接