使用 R 在特定列中随机对数据帧进行子采样而不进行替换
Randomly subsampling a dataframe without replacements in a specific column with R
我有一个具有这种结构的数据框:
> df
factor y x
1 2 0
1 3 0
1 1 0
1 2 0
2 3 0
2 1 0
2 3 1
3 4 1
3 3 1
3 6 3
3 5 2
4 4 1
4 7 8
4 2 1
2 5 3
在实际数据集中,我有 200 行和不同的变量:几个连续变量和一个具有 70 个水平的因子变量,每个水平最多有 4 个观察值。
我想将我的整个数据帧随机抽样为 4 个大小相等的组,而不在每个组内仅在因子变量中进行替换。换句话说,我希望每组因子变量的每个级别出现不超过一次。
我尝试过不同的解决方案。
例如,我尝试通过将“因子”变量抽样为四组而不进行替换,如下所示:
factor1 <- as.character(df$factor)
set.seed(123)
group1 <- sample(factor, 35,replace = FALSE)
factor2 <- setdiff(factor1, group1)
group2 <- sample(factor2, 35,replace = FALSE)
# and the same for "group3" and "group4"
但是我不知道如何将组向量(group1、group2 等)关联到我的 df 中的其他变量('x' 和 'y')。
我也尝试过:
group1 <- sample_n(df, 35, replace = FALSE)
但是这个解决方案也失败了,因为我的数据框不包含重复的行。唯一重复的值在因子变量中。
最后,我尝试使用在回答类似问题here时提出的解决方案,适用于我的情况:
random.groups <- function(n.items = 200L, n.groups = 4L,
factor = rep(1L, n.items)) {
splitted.items <- split(seq.int(n.items), factor)
shuffled <- lapply(splitted.items, sample)
1L + (order(unlist(shuffled)) %% n.groups)
}
df$groups <- random.groups(nrow(df), n.groups = 4)
但是,生成的 4 个组包含因子变量的重复值,因此有些地方无法正常工作。
如果有任何解决此问题的想法或建议,我将不胜感激!
一种方法是按因子分组,创建一个因子长度的变量,按大小和长度排列。最后,您为第一、第二、第三和第四行各分配一个组。然后您可以使用此变量过滤掉。
library(dplyr)
df <- data_frame(factor = c(1,1,1,1,2,2,2,3,3,3,3,4,4,4,2),
x = floor(runif(15, min=0, max=20)),
y = floor(runif(15, min=211, max=305)))
df <- df %>% group_by(factor) %>% mutate(size = length(factor)) %>% arrange(desc(size), factor) %>%
ungroup() %>% mutate(group = ifelse(row_number() %% 4 == 1, "A",
ifelse(row_number() %% 4 == 2, "B",
ifelse(row_number() %% 4 == 3, "C", "D"))))
一个 data.table
解决方案用稍大的数据集演示:
library(data.table)
dt <- setorder(data.table(factor = sample(10, 44, TRUE), x = runif(44), y = runif(44)), factor)
numGroups <- 4L
maxFactor <- max(dt$factor)
dt2 <- setorder(
setorder(
dt[sample(.N, .N)], # randomly reorder the data
factor # sort by factor
)[, temp := cumsum(.I > 0), by = factor] # create a column to keep a running count of the occurrence of each factor
[temp <= numGroups] # remove rows that can't go in a group due to factor exclusion
[sample(.N, .N) <= (.N %/% numGroups)*numGroups] # randomly remove excess rows (keep the group sizes equal)
[, temp := sample(10, 10)[factor]] # randomly reorder factor groups
[, grp := c(rep(1:numGroups, .N/numGroups))], # assign each row a group: row 1 -> group 1, row 2 -> group 2 ... 5 -> 1, 6 -> 2, etc.
grp # sort by group for table readability
)[, temp := NULL] # remove the temporary column
结果 data.table
将有 numGroups
个组,如 grp
列所示。每组将具有相同的行数。为了满足无重复因子约束,每组中的行数将是最大可能的。对于较小的样本,取 dt2
的子样本(参见 this question)。
我有一个具有这种结构的数据框:
> df
factor y x
1 2 0
1 3 0
1 1 0
1 2 0
2 3 0
2 1 0
2 3 1
3 4 1
3 3 1
3 6 3
3 5 2
4 4 1
4 7 8
4 2 1
2 5 3
在实际数据集中,我有 200 行和不同的变量:几个连续变量和一个具有 70 个水平的因子变量,每个水平最多有 4 个观察值。
我想将我的整个数据帧随机抽样为 4 个大小相等的组,而不在每个组内仅在因子变量中进行替换。换句话说,我希望每组因子变量的每个级别出现不超过一次。
我尝试过不同的解决方案。 例如,我尝试通过将“因子”变量抽样为四组而不进行替换,如下所示:
factor1 <- as.character(df$factor)
set.seed(123)
group1 <- sample(factor, 35,replace = FALSE)
factor2 <- setdiff(factor1, group1)
group2 <- sample(factor2, 35,replace = FALSE)
# and the same for "group3" and "group4"
但是我不知道如何将组向量(group1、group2 等)关联到我的 df 中的其他变量('x' 和 'y')。
我也尝试过:
group1 <- sample_n(df, 35, replace = FALSE)
但是这个解决方案也失败了,因为我的数据框不包含重复的行。唯一重复的值在因子变量中。
最后,我尝试使用在回答类似问题here时提出的解决方案,适用于我的情况:
random.groups <- function(n.items = 200L, n.groups = 4L,
factor = rep(1L, n.items)) {
splitted.items <- split(seq.int(n.items), factor)
shuffled <- lapply(splitted.items, sample)
1L + (order(unlist(shuffled)) %% n.groups)
}
df$groups <- random.groups(nrow(df), n.groups = 4)
但是,生成的 4 个组包含因子变量的重复值,因此有些地方无法正常工作。
如果有任何解决此问题的想法或建议,我将不胜感激!
一种方法是按因子分组,创建一个因子长度的变量,按大小和长度排列。最后,您为第一、第二、第三和第四行各分配一个组。然后您可以使用此变量过滤掉。
library(dplyr)
df <- data_frame(factor = c(1,1,1,1,2,2,2,3,3,3,3,4,4,4,2),
x = floor(runif(15, min=0, max=20)),
y = floor(runif(15, min=211, max=305)))
df <- df %>% group_by(factor) %>% mutate(size = length(factor)) %>% arrange(desc(size), factor) %>%
ungroup() %>% mutate(group = ifelse(row_number() %% 4 == 1, "A",
ifelse(row_number() %% 4 == 2, "B",
ifelse(row_number() %% 4 == 3, "C", "D"))))
一个 data.table
解决方案用稍大的数据集演示:
library(data.table)
dt <- setorder(data.table(factor = sample(10, 44, TRUE), x = runif(44), y = runif(44)), factor)
numGroups <- 4L
maxFactor <- max(dt$factor)
dt2 <- setorder(
setorder(
dt[sample(.N, .N)], # randomly reorder the data
factor # sort by factor
)[, temp := cumsum(.I > 0), by = factor] # create a column to keep a running count of the occurrence of each factor
[temp <= numGroups] # remove rows that can't go in a group due to factor exclusion
[sample(.N, .N) <= (.N %/% numGroups)*numGroups] # randomly remove excess rows (keep the group sizes equal)
[, temp := sample(10, 10)[factor]] # randomly reorder factor groups
[, grp := c(rep(1:numGroups, .N/numGroups))], # assign each row a group: row 1 -> group 1, row 2 -> group 2 ... 5 -> 1, 6 -> 2, etc.
grp # sort by group for table readability
)[, temp := NULL] # remove the temporary column
结果 data.table
将有 numGroups
个组,如 grp
列所示。每组将具有相同的行数。为了满足无重复因子约束,每组中的行数将是最大可能的。对于较小的样本,取 dt2
的子样本(参见 this question)。