使用特定于组的样本大小从数据框中抽样
Sample from a data frame using group-specific sample sizes
我想使用每个组中不相等的样本大小从数据框中对行进行采样。
假设我们有一个按 'group':
分组的简单数据框
library(dplyr)
set.seed(123)
df <- data.frame(group = rep(c("A", "B"), each = 10),
value = rnorm(10))
df
#> group value
#> 1 A -0.56047565
#> 2 A -0.23017749
#> .....
#> 10 A -0.44566197
#> 11 B -0.56047565
#> 12 B -0.23017749
#> .....
#> 20 B -0.44566197
使用 dplyr
包中的 slice_sample
函数,您可以轻松地从此数据帧中分割 等 大小的组:
df %>% group_by(group) %>% slice_sample(n = 2) %>% ungroup()
#> # A tibble: 4 x 2
#> group value
#> <fct> <dbl>
#> 1 A -0.687
#> 2 A -0.446
#> 3 B -0.687
#> 4 B 1.56
问题
如何从每个组(大小不相等的切片组)中抽取 不同 个值?比如A组抽取4行,B组抽取5行?
试试这个:
group_sizes <- tibble(group = c("A", "B"), size = c(4, 5))
set.seed(2021)
df %>%
left_join(group_sizes, by = "group") %>%
group_by(group) %>%
mutate(samp = sample(n())) %>%
filter(samp <= size) %>%
ungroup()
# # A tibble: 9 x 4
# group value size samp
# <chr> <dbl> <dbl> <int>
# 1 A 0.0705 4 2
# 2 A 0.129 4 4
# 3 A -0.687 4 1
# 4 A -0.446 4 3
# 5 B -0.560 5 5
# 6 B 1.56 5 1
# 7 B 0.129 5 4
# 8 B 1.72 5 3
# 9 B -1.27 5 2
a data.table
方法,使用 mapply
循环列表元素与向量中的样本大小(列表长度!)
library( data.table )
setDT(df) #make it a data.table
L <- split( df, by = "group" ) #split to a list by group
#function
mysamples <- function( dt, samplesize ) {
dt[ sample( 1:nrow(dt), samplesize), ]
}
#mapply
mapply( mysamples, L, samplesize = c(4,5), SIMPLIFY = FALSE )
#output
# $A
# group value
# 1: A -0.6868529
# 2: A -0.4456620
# 3: A -0.5604756
# 4: A 0.1292877
#
# $B
# group value
# 1: B 1.5587083
# 2: B -1.2650612
# 3: B -0.2301775
# 4: B 0.4609162
# 5: B -0.6868529
set.seed(123)
library(tidyverse)
map2_df(unique(df$group), c(4,5),
~df %>%
filter(group == .x) %>%
slice_sample(n = .y))
group value
1 A -0.3724388
2 A -0.4168576
3 A 0.5629895
4 A -1.2601552
5 B 1.0527115
6 B -0.3745809
7 B 0.9769734
8 B -0.4168576
9 B -1.0491770
如果您的数据还没有整理好,您可以使用以下方法:
map2_df(unique(sort(df$group)), c(4,5),
~df %>% arrange(group) %>%
filter(group == .x) %>%
slice_sample(n = .y))
我能想到的最简单的事情是 map2
使用 purrr
的解决方案。
library(dplyr)
library(purrr)
df %>%
group_split(group) %>%
map2_dfr(c(4, 5), ~ slice_sample(.x, n = .y))
# A tibble: 9 x 2
group value
<chr> <dbl>
1 A -0.687
2 A 1.56
3 A 0.0705
4 A 1.72
5 B -0.560
6 B 0.461
7 B 0.129
8 B 0.0705
9 B -0.230
请注意,您需要了解拆分的顺序。我认为 group_split()
会将组作为因素进行排序。一种解决方法是像这样进行调整,并从命名向量中查找 n
。
group_slice_n <- c(A = 4, B = 5)
df %>%
split(.$group) %>%
imap_dfr(~ slice_sample(.x, n = group_slice_n[.y]))
另一种 data.table
可能性基于连接。
将特定于组的样本大小放入“查找 table”(这里是一个列表,.(...)
);在 'group' (on = .(group)
) 上加入原始数据;对于 i
(by = .EACHI
) 中的每个匹配项,从 'value' 中选择一个大小 = size[1]
)
的样本
setDT(df)[.(group = c("A", "B"), size = c(4, 5)), on = .(group), sample(value, size[1]),
by = .EACHI]
# group V1
# 1: A -0.6868529
# 2: A -0.4456620
# 3: A -0.5604756
# 4: A 0.1292877
# 5: B 1.5587083
# 6: B -1.2650612
# 7: B -0.2301775
# 8: B 0.4609162
# 9: B -0.6868529
您可以使用我的“splitstackshape”包中的 stratified
函数:
> library(splitstackshape)
> stratified(df, "group", c(A = 4, B = 5))
group value
1: A -0.6868529
2: A 0.4609162
3: A 1.7150650
4: A -0.4456620
5: B 0.4609162
6: B -0.4456620
7: B 0.1292877
8: B -1.2650612
9: B -0.2301775
我想使用每个组中不相等的样本大小从数据框中对行进行采样。
假设我们有一个按 'group':
分组的简单数据框library(dplyr)
set.seed(123)
df <- data.frame(group = rep(c("A", "B"), each = 10),
value = rnorm(10))
df
#> group value
#> 1 A -0.56047565
#> 2 A -0.23017749
#> .....
#> 10 A -0.44566197
#> 11 B -0.56047565
#> 12 B -0.23017749
#> .....
#> 20 B -0.44566197
使用 dplyr
包中的 slice_sample
函数,您可以轻松地从此数据帧中分割 等 大小的组:
df %>% group_by(group) %>% slice_sample(n = 2) %>% ungroup()
#> # A tibble: 4 x 2
#> group value
#> <fct> <dbl>
#> 1 A -0.687
#> 2 A -0.446
#> 3 B -0.687
#> 4 B 1.56
问题
如何从每个组(大小不相等的切片组)中抽取 不同 个值?比如A组抽取4行,B组抽取5行?
试试这个:
group_sizes <- tibble(group = c("A", "B"), size = c(4, 5))
set.seed(2021)
df %>%
left_join(group_sizes, by = "group") %>%
group_by(group) %>%
mutate(samp = sample(n())) %>%
filter(samp <= size) %>%
ungroup()
# # A tibble: 9 x 4
# group value size samp
# <chr> <dbl> <dbl> <int>
# 1 A 0.0705 4 2
# 2 A 0.129 4 4
# 3 A -0.687 4 1
# 4 A -0.446 4 3
# 5 B -0.560 5 5
# 6 B 1.56 5 1
# 7 B 0.129 5 4
# 8 B 1.72 5 3
# 9 B -1.27 5 2
a data.table
方法,使用 mapply
循环列表元素与向量中的样本大小(列表长度!)
library( data.table )
setDT(df) #make it a data.table
L <- split( df, by = "group" ) #split to a list by group
#function
mysamples <- function( dt, samplesize ) {
dt[ sample( 1:nrow(dt), samplesize), ]
}
#mapply
mapply( mysamples, L, samplesize = c(4,5), SIMPLIFY = FALSE )
#output
# $A
# group value
# 1: A -0.6868529
# 2: A -0.4456620
# 3: A -0.5604756
# 4: A 0.1292877
#
# $B
# group value
# 1: B 1.5587083
# 2: B -1.2650612
# 3: B -0.2301775
# 4: B 0.4609162
# 5: B -0.6868529
set.seed(123)
library(tidyverse)
map2_df(unique(df$group), c(4,5),
~df %>%
filter(group == .x) %>%
slice_sample(n = .y))
group value
1 A -0.3724388
2 A -0.4168576
3 A 0.5629895
4 A -1.2601552
5 B 1.0527115
6 B -0.3745809
7 B 0.9769734
8 B -0.4168576
9 B -1.0491770
如果您的数据还没有整理好,您可以使用以下方法:
map2_df(unique(sort(df$group)), c(4,5),
~df %>% arrange(group) %>%
filter(group == .x) %>%
slice_sample(n = .y))
我能想到的最简单的事情是 map2
使用 purrr
的解决方案。
library(dplyr)
library(purrr)
df %>%
group_split(group) %>%
map2_dfr(c(4, 5), ~ slice_sample(.x, n = .y))
# A tibble: 9 x 2
group value
<chr> <dbl>
1 A -0.687
2 A 1.56
3 A 0.0705
4 A 1.72
5 B -0.560
6 B 0.461
7 B 0.129
8 B 0.0705
9 B -0.230
请注意,您需要了解拆分的顺序。我认为 group_split()
会将组作为因素进行排序。一种解决方法是像这样进行调整,并从命名向量中查找 n
。
group_slice_n <- c(A = 4, B = 5)
df %>%
split(.$group) %>%
imap_dfr(~ slice_sample(.x, n = group_slice_n[.y]))
另一种 data.table
可能性基于连接。
将特定于组的样本大小放入“查找 table”(这里是一个列表,.(...)
);在 'group' (on = .(group)
) 上加入原始数据;对于 i
(by = .EACHI
) 中的每个匹配项,从 'value' 中选择一个大小 = size[1]
)
setDT(df)[.(group = c("A", "B"), size = c(4, 5)), on = .(group), sample(value, size[1]),
by = .EACHI]
# group V1
# 1: A -0.6868529
# 2: A -0.4456620
# 3: A -0.5604756
# 4: A 0.1292877
# 5: B 1.5587083
# 6: B -1.2650612
# 7: B -0.2301775
# 8: B 0.4609162
# 9: B -0.6868529
您可以使用我的“splitstackshape”包中的 stratified
函数:
> library(splitstackshape)
> stratified(df, "group", c(A = 4, B = 5))
group value
1: A -0.6868529
2: A 0.4609162
3: A 1.7150650
4: A -0.4456620
5: B 0.4609162
6: B -0.4456620
7: B 0.1292877
8: B -1.2650612
9: B -0.2301775