在数据框中,对每个组随机抽取n行样本。
在数据框中,对每个组随机抽取n行样本。
从这些问题中 - 从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), ] #从df中随机抽取3行,无重复。
例如,只从'pink'颜色中随机抽取3行 - 使用library(kimisc)
:
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)行。即新的df将有12行(3行来自蓝色,3行来自红色,3行来自黄色,3行来自粉色)。显然可以多次运行这个过程,为每种颜色创建新的df,然后将它们绑定在一起,但我正在寻找一个更简单的解决方案。
问题出现的原因:用户想要从数据框中每个组中随机抽取n个样本,以满足卡方检验的样本大小条件。
解决方法:用户可以使用ave函数为具有特定因子水平的每个元素分配一个随机ID。然后,可以选择在特定范围内的所有随机ID。
代码如下:
rndid <- with(df, ave(X1, color, FUN=function(x) {sample.int(length(x))})) df[rndid<=n,]
这种方法的优点是保留了原始行顺序和行名称(如果用户对此感兴趣的话)。此外,用户可以轻松地重用rndid向量来创建不同长度的子集。
在回答者与提问者的对话中,有两个问题需要解决。问题1)变量X1,选择数据框中的哪个变量似乎并不重要。问题2)当不同因子水平的观测数量不同时,该解决方案仍然有效。即,如果用户要求每个颜色抽取11行,它将返回10行。在真实数据中,这可能很有用,因为不同因子水平的观测/行数确实有所不同。
用户对解决方案的反馈是满意的,即使存在不平衡的组也可以正常工作。
然后,用户提出了一个新的问题,即如何使用解决方案来满足卡方检验的样本大小条件,即每个组至少抽取5个样本。
根据之前的解决方案,我们可以修改代码如下:
rndid <- with(df, ave(X1, color, FUN=function(x) {sample.int(length(x))})) df2 <- df[rndid<=n,] df3 <- df2[ave(df2$color, df2$color, FUN=function(x) {sum(x) >= 5}),]
在这个修改后的代码中,我们首先使用之前的方法随机抽取了n个样本。然后,我们使用ave函数计算每个颜色组的样本数量,并通过检查是否大于等于5来筛选出满足样本大小条件的组。
这样,用户就可以使用这个修改后的代码满足卡方检验的样本大小条件了。
问题的出现原因:在旧版本的dplyr(版本<=0.2)中,使用group_by和sample_n函数组合时,会出现问题,因为sample_n.grouped_df方法存在但没有在NAMESPACE文件中注册,导致无法调用该方法。
解决方法:在旧版本的dplyr中,可以通过显式调用dplyr:::sample_n.grouped_df方法来解决该问题。具体操作是先使用group_by函数对数据进行分组,然后使用dplyr:::sample_n.grouped_df函数进行抽样。
这个问题在dplyr 0.3版本中已经修复。
文章内容如下:
在dplyr的0.3版本及以后的版本中,下面的代码可以正常工作:
df %>% group_by(color) %>% sample_n(size = 3)
然而,在旧版本的dplyr(版本<=0.2)中,使用相同的代码会出现问题。在0.2版本中,虽然存在sample_n.grouped_df的S3方法,但没有在NAMESPACE文件中注册,所以无法调用该方法。为了解决这个问题,可以通过显式调用dplyr:::sample_n.grouped_df方法来进行抽样。具体操作是先使用group_by函数对数据进行分组,然后使用dplyr:::sample_n.grouped_df函数进行抽样。
以下是使用修复方法后的代码和输出结果:
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版本是多少?是trunk版本吗?
我尝试过使用cran上的0.2版本和从github安装的版本,结果都是一样的。
在dplyr 0.3版本中,这个问题得到了解决。这是我现在解决这个问题的最喜欢的方法。
有人能解释一下这个方法的概念吗?sample_n函数是否会回溯查看是否应用了group_by函数?
管道操作符%>%将每个步骤的结果传递给下一个函数,所以不需要“回溯”。运行x <- mtcars %>% group_by(cyl),然后查看x,你会发现它有一个新的class属性,以及许多其他属性(attributes(x)),所以任何后续的函数都“知道”它正在处理一个分组的数据框。
然后,许多其他的dplyr函数将具有专门针对grouped_df对象的S3方法。可以使用methods(sample_n)来查看。
这个方法与sample_frac函数很好地配合使用,以保持各类别的相对比例。
现在,在dplyr中可以使用slice_sample函数来实现这个功能。具体请参考dplyr的官方文档:https://dplyr.tidyverse.org/reference/slice.html