r 生成一个带有随机 1 和 0 的列,但有限制
r generate a column with random 1s and 0s with restrictions
我有一个包含 500 个观察值的数据集。我喜欢根据两种情况随机生成1和0
当前数据集
Id Age Category
1 23 1
2 24 1
3 21 2
. . .
. . .
. . .
500 27 3
场景一
- 1的总数应该是200个,并且应该是随机的。剩下的300应该是0。
场景二
- 1的总数应该是200个,剩下的300个应该是0。
- 40% 的 1 应该属于 Category1。即80个1应该属于Category1
- 40%的1应该属于Category2 即80个1应该属于Category2
- 20%的1应该属于Category3 即40个1应该属于Category3
预期输出
Id Age Category Indicator
1 23 1 1
2 24 1 0
3 21 2 1
. . .
. . .
. . .
500 27 3 1
我知道函数 sample(c(0,1), 500)
会生成 1,但我不知道如何让它随机生成 200 个 1。也不确定如何在 Category1 中随机生成 80 个 1,在 Category2 中随机生成 80 个 1,在 Category3 中随机生成 40 个 1。
要解决方案 1,您需要创建一个包含 300 个零和 200 个一的向量,然后从中创建相同的向量而无需替换。
pull_from = c(rep(0,300), rep(1,200))
sample(pull_from, replace = FALSE)
对于方案 2,我建议您根据类别将数据分成 3 个单独的块,重复上述步骤,为您需要的 0 和 1 的数量设置不同的值,然后重新组合成一个数据帧。
这是一个完整的示例。
假设您的数据如下所示:
set.seed(69)
df <- data.frame(id = 1:500,
Age = 20 + sample(10, 500, TRUE),
Category = sample(3, 500, TRUE))
head(df)
#> id Age Category
#> 1 1 21 2
#> 2 2 22 2
#> 3 3 28 3
#> 4 4 27 2
#> 5 5 27 1
#> 6 6 26 2
现在,你没有提到每个类别有多少,所以让我们检查一下样本中有多少:
table(df$Category)
#> 1 2 3
#> 153 179 168
场景 1 很简单。您需要创建一个包含 500 个零的向量,然后将一个 1 写入新向量的 索引 的样本 200 中:
df$label <- numeric(nrow(df))
df$label[sample(nrow(df), 200)] <- 1
head(df)
#> id Age Category label
#> 1 1 21 2 1
#> 2 2 22 2 1
#> 3 3 28 3 0
#> 4 4 27 2 0
#> 5 5 27 1 0
#> 6 6 26 2 1
所以我们有随机的 0 和 1,但是当我们计算它们时,我们有:
table(df$label)
#>
#> 0 1
#> 300 200
场景2类似但复杂一点,因为我们需要按类别进行类似的操作groupwise:
df$label <- numeric(nrow(df))
df <- do.call("rbind", lapply(split(df, df$Category), function(d) {
n_ones <- round(nrow(d) * 0.4 / ((d$Category[1] %/% 3) + 1))
d$label[sample(nrow(d), n_ones)] <- 1
d
}))
head(df)
#> id Age Category label
#> 1.5 5 27 1 0
#> 1.10 10 24 1 0
#> 1.13 13 23 1 1
#> 1.19 19 24 1 0
#> 1.26 26 22 1 1
#> 1.27 27 24 1 1
现在,由于每个类别中的数字不能很好地被 10 整除,我们无法精确地得到 40% 和 20%(尽管您可能会使用自己的数据),但我们会尽可能接近它,因为下面演示:
label_table <- table(df$Category, df$label)
label_table
#> 0 1
#> 1 92 61
#> 2 107 72
#> 3 134 34
apply(label_table, 1, function(x) x[2]/sum(x))
#> 1 2 3
#> 0.3986928 0.4022346 0.2023810
由 reprex package (v0.3.0)
于 2020-08-12 创建
另一种填充随机值的方法是创建一个可能值的向量(80 个值为 1,nrow-80 个值为 0),然后从这些可能值中采样。这可能比通过索引设置值使用更多的内存,但是潜在值的向量非常小,通常是微不足道的。
set.seed(42)
df <- data.frame(id = 1:500,
Age = 20 + sample(10, 500, TRUE),
Category = sample(3, 500, TRUE))
## In Tidyverse
library(tidyverse)
set.seed(42)
df2 <- df %>%
group_by(Category) %>%
mutate(Label = case_when(
Category == 1 ~ sample(
c(rep(1,80),rep(0,n()-80)),
n()
),
Category == 2 ~ sample(
c(rep(1,80),rep(0,n()-80)),
n()
),
Category == 3 ~ sample(
c(rep(1,40),rep(0,n()-40)),
n()
)
))
table(df2$Category,df2$Label)
# 0 1
# 1 93 80
# 2 82 80
# 3 125 40
## In base
df3 <- df
df3[df$Category == 1,"Label"] <- sample(
c(rep(1,80),rep(0,nrow(df[df$Category == 1,])-80)),
nrow(df[df$Category == 1,])
)
df3[df$Category == 2,"Label"] <- sample(
c(rep(1,80),rep(0,nrow(df[df$Category == 2,])-80)),
nrow(df[df$Category == 2,])
)
df3[df$Category == 3,"Label"] <- sample(
c(rep(1,40),rep(0,nrow(df[df$Category == 3,])-40)),
nrow(df[df$Category == 3,])
)
table(df3$Category,df3$Label)
# 0 1
# 1 93 80
# 2 82 80
# 3 125 40
我有一个包含 500 个观察值的数据集。我喜欢根据两种情况随机生成1和0
当前数据集
Id Age Category
1 23 1
2 24 1
3 21 2
. . .
. . .
. . .
500 27 3
场景一
- 1的总数应该是200个,并且应该是随机的。剩下的300应该是0。
场景二
- 1的总数应该是200个,剩下的300个应该是0。
- 40% 的 1 应该属于 Category1。即80个1应该属于Category1
- 40%的1应该属于Category2 即80个1应该属于Category2
- 20%的1应该属于Category3 即40个1应该属于Category3
预期输出
Id Age Category Indicator
1 23 1 1
2 24 1 0
3 21 2 1
. . .
. . .
. . .
500 27 3 1
我知道函数 sample(c(0,1), 500)
会生成 1,但我不知道如何让它随机生成 200 个 1。也不确定如何在 Category1 中随机生成 80 个 1,在 Category2 中随机生成 80 个 1,在 Category3 中随机生成 40 个 1。
要解决方案 1,您需要创建一个包含 300 个零和 200 个一的向量,然后从中创建相同的向量而无需替换。
pull_from = c(rep(0,300), rep(1,200))
sample(pull_from, replace = FALSE)
对于方案 2,我建议您根据类别将数据分成 3 个单独的块,重复上述步骤,为您需要的 0 和 1 的数量设置不同的值,然后重新组合成一个数据帧。
这是一个完整的示例。
假设您的数据如下所示:
set.seed(69)
df <- data.frame(id = 1:500,
Age = 20 + sample(10, 500, TRUE),
Category = sample(3, 500, TRUE))
head(df)
#> id Age Category
#> 1 1 21 2
#> 2 2 22 2
#> 3 3 28 3
#> 4 4 27 2
#> 5 5 27 1
#> 6 6 26 2
现在,你没有提到每个类别有多少,所以让我们检查一下样本中有多少:
table(df$Category)
#> 1 2 3
#> 153 179 168
场景 1 很简单。您需要创建一个包含 500 个零的向量,然后将一个 1 写入新向量的 索引 的样本 200 中:
df$label <- numeric(nrow(df))
df$label[sample(nrow(df), 200)] <- 1
head(df)
#> id Age Category label
#> 1 1 21 2 1
#> 2 2 22 2 1
#> 3 3 28 3 0
#> 4 4 27 2 0
#> 5 5 27 1 0
#> 6 6 26 2 1
所以我们有随机的 0 和 1,但是当我们计算它们时,我们有:
table(df$label)
#>
#> 0 1
#> 300 200
场景2类似但复杂一点,因为我们需要按类别进行类似的操作groupwise:
df$label <- numeric(nrow(df))
df <- do.call("rbind", lapply(split(df, df$Category), function(d) {
n_ones <- round(nrow(d) * 0.4 / ((d$Category[1] %/% 3) + 1))
d$label[sample(nrow(d), n_ones)] <- 1
d
}))
head(df)
#> id Age Category label
#> 1.5 5 27 1 0
#> 1.10 10 24 1 0
#> 1.13 13 23 1 1
#> 1.19 19 24 1 0
#> 1.26 26 22 1 1
#> 1.27 27 24 1 1
现在,由于每个类别中的数字不能很好地被 10 整除,我们无法精确地得到 40% 和 20%(尽管您可能会使用自己的数据),但我们会尽可能接近它,因为下面演示:
label_table <- table(df$Category, df$label)
label_table
#> 0 1
#> 1 92 61
#> 2 107 72
#> 3 134 34
apply(label_table, 1, function(x) x[2]/sum(x))
#> 1 2 3
#> 0.3986928 0.4022346 0.2023810
由 reprex package (v0.3.0)
于 2020-08-12 创建另一种填充随机值的方法是创建一个可能值的向量(80 个值为 1,nrow-80 个值为 0),然后从这些可能值中采样。这可能比通过索引设置值使用更多的内存,但是潜在值的向量非常小,通常是微不足道的。
set.seed(42)
df <- data.frame(id = 1:500,
Age = 20 + sample(10, 500, TRUE),
Category = sample(3, 500, TRUE))
## In Tidyverse
library(tidyverse)
set.seed(42)
df2 <- df %>%
group_by(Category) %>%
mutate(Label = case_when(
Category == 1 ~ sample(
c(rep(1,80),rep(0,n()-80)),
n()
),
Category == 2 ~ sample(
c(rep(1,80),rep(0,n()-80)),
n()
),
Category == 3 ~ sample(
c(rep(1,40),rep(0,n()-40)),
n()
)
))
table(df2$Category,df2$Label)
# 0 1
# 1 93 80
# 2 82 80
# 3 125 40
## In base
df3 <- df
df3[df$Category == 1,"Label"] <- sample(
c(rep(1,80),rep(0,nrow(df[df$Category == 1,])-80)),
nrow(df[df$Category == 1,])
)
df3[df$Category == 2,"Label"] <- sample(
c(rep(1,80),rep(0,nrow(df[df$Category == 2,])-80)),
nrow(df[df$Category == 2,])
)
df3[df$Category == 3,"Label"] <- sample(
c(rep(1,40),rep(0,nrow(df[df$Category == 3,])-40)),
nrow(df[df$Category == 3,])
)
table(df3$Category,df3$Label)
# 0 1
# 1 93 80
# 2 82 80
# 3 125 40