在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
或者,可以使用首先不更改列顺序的base
R 解决方案
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)))
可能还有其他十几种方法可以做到这一点,而且可能是我没有想到的更有效的方法。