r语言 - 具有随机布尔值的新列,同时控制每个类别的 TRUE/FALSE 比率



在R中,我有一个这样的数据集:

df <- data.frame(
ID = c(1:30),
x1 = seq(0, 1, length.out = 30),
x2 = seq(100, 3000, length.out = 30),
category = gl(3, 10, labels = c("NEGATIVE", "NEUTRAL", "POSITIVE"))
)

现在我想添加一个具有随机布尔值的新列,但是在每个类别中,TRUE 和 FALSE 值的比例应该相同(即随机化过程应生成相同的真值和假值计数,在上面的数据框中,3 个类别中每个类别中每个类别中的 5 个 TRUE 和 5 个 FALSE)。怎么做?

您可以对"TRUE"和"FALSE"值的向量进行采样而无需替换,因此您的数据框中有一个随机和平衡的列。

sample(rep(c("TRUE","FALSE"),each=5),10,replace=FALSE)

基于 Yacine Hajji 的回答:

addRandomBool <- function(df, p){

n <- ceiling(nrow(df) * p)
df$bool <- sample(rep(c("TRUE","FALSE"), times = c(n, nrow(df) - n)))

df
}
Reduce(rbind, lapply(split(df, df$category), addRandomBool, p = 0.5))

其中,帕拉梅塔尔p确定TRUE的比例。

这将从 5 个 TRUE 和 5 FALSE 的向量中在每个组中采样,而无需替换。它将假定每组始终有 10 条记录。

library(dplyr)
library(tidyr)
df <- data.frame(
ID = c(1:30),
x1 = seq(0, 1, length.out = 30),
x2 = seq(100, 3000, length.out = 30),
category = gl(3, 10, labels = c("NEGATIVE", "NEUTRAL", "POSITIVE"))
)
set.seed(pi)
df %>% 
group_by(category) %>% 
nest() %>% 
mutate(data = lapply(data, 
function(df){ # Function to saple and assign the new_col
df$new_col <- sample(rep(c(FALSE, TRUE), 
each = 5), 
size = 10, 
replace = FALSE)
df
})) %>% 
unnest(cols = "data")

下一个示例稍微通用一些,但仍假设(大致)TRUE 和 FALSE 在组中均匀分布。 但它可以适应可变的组大小,以及具有奇数条记录的偶数组(但对于奇数条记录,将倾向于使用 FALSE)

library(dplyr)
library(tidyr)
df <- data.frame(
ID = c(1:30),
x1 = seq(0, 1, length.out = 30),
x2 = seq(100, 3000, length.out = 30),
category = gl(3, 10, labels = c("NEGATIVE", "NEUTRAL", "POSITIVE"))
)
set.seed(pi)
df %>% 
group_by(category) %>% 
nest() %>% 
mutate(data = lapply(data, 
function(df){
df$new_col <- sample(rep(c(FALSE, TRUE), 
length.out = nrow(df)), 
size = nrow(df), 
replace = FALSE)
df
})) %>% 
unnest(cols = "data")

维护列顺序

维护列顺序的几个选项:

首先,您可以在执行group_by - nest之前保存列顺序,然后在完成后使用select设置顺序。

set.seed(pi)
orig_col <- names(df)  # original column order
df %>% 
group_by(category) %>% 
nest() %>% 
mutate(data = lapply(data, 
function(df){
df$new_col <- sample(rep(c(FALSE, TRUE), 
length.out = nrow(df)), 
size = nrow(df), 
replace = FALSE)
df
})) %>% 
unnest(cols = "data") %>% 
select_at(c(orig_col, "new_col"))   # Restore the column order

或者,可以使用首先不更改列顺序的baseR 解决方案

df <- split(df, df["category"])
df <- lapply(df, 
function(df){
df$new_col <- sample(rep(c(FALSE, TRUE), 
length.out = nrow(df)), 
size = nrow(df), 
replace = FALSE)
df
})
do.call("rbind", c(df, list(make.row.names = FALSE)))

可能还有其他十几种方法可以做到这一点,而且可能是我没有想到的更有效的方法。

最新更新