用不等于 0 的样本替换值
Replace values with a sample not equal to 0
我想使用 sample
替换我的数据集中的 0 以在列中随机 select 一个值来替换它。
我有这个示例数据集:
Sepal.Length Sepal.Width Petal.Length Petal.Width species
1 0.0 3.5 0.0 0.2 setosa
2 4.9 3.0 0.0 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.0 setosa
5 5.0 0.0 0.0 0.0 setosa
6 0.0 0.0 0.0 0.4 setosa
我试过:
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
[1] 3.5 3.0 3.2 3.1 0.0 0.0 3.4 1.0 2.9 1.0 3.7 1.0 3.0 3.0 4.0
零仍然存在。我尝试对所有列进行循环,因为对每一列执行上面的代码太耗时了,我已经尝试过:
lapply(ir[,-5], function(x)ifelse(ir[,1:4] == 0, sample(ir[,1:4]),ir[,1:4]))
然而,它会创建不必要的数据列,并且仍然保留零。
可重现代码:
structure(list(Sepal.Length = c(0, 4.9, 4.7, 4.6, 5, 0, 4.6,
5, 4.4, 0, 5.4, 4.8, 0, 0, 0), Sepal.Width = c(3.5, 3, 3.2, 3.1,
0, 0, 3.4, 0, 2.9, 0, 3.7, 0, 3, 3, 4), Petal.Length = c(0, 0,
1.3, 1.5, 0, 0, 1.4, 1.5, 1.4, 1.5, 0, 1.6, 1.4, 1.1, 1.2), Petal.Width = c(0.2,
0.2, 0.2, 0, 0, 0.4, 0.3, 0.2, 0.2, 0, 0.2, 0, 0, 0, 0.2), species = structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("setosa",
"versicolor", "virginica"), class = "factor")), row.names = c(NA,
15L), class = "data.frame")
用向量中的随机非零值替换零的函数:
f <- function(vec){
ind <- vec == 0
vec[ind] <- sample(vec[!ind], sum(ind), TRUE)
vec
}
将函数 f
应用于每个数字列:
library(data.table)
num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
setDT(df)[, (num_cols) := lapply(.SD, f), .SD = num_cols]
或使用基数 R
num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
df[num_cols] <- lapply(df[num_cols], f)
注
最好使用 Advanced R 书中的 sample
函数:
sample <- function(x, size = NULL, replace = FALSE, prob = NULL) {
size <- size %||% length(x)
x[sample.int(length(x), size, replace = replace, prob = prob)]
}
因为 base::sample
在 x
是长度为 1 的数字的情况下的行为。
这是一个简短的 dplyr
解决方案:
ir %>%
mutate(across(.cols = where(is.numeric),
~ replace(., . == 0, sample(.[. != 0], length(.[. == 0]), replace=T))))
您可能需要也可能不需要 replace=T
,它允许重复采样元素。
使用 data.table (library(data.table)
):
setDT(ir)
ir[, Sepal.Width :=
ifelse(Sepal.Width==0,
sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE),
Sepal.Width),
by=species]
您也可以通过添加 by
从同一物种中取样
setDT(ir)
ir[, Sepal.Width :=
ifelse(Sepal.Width==0,
sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE),
Sepal.Width),
by=species]
为所有课程获取此信息:
ir[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") :=
lapply(.SD, function(x) {
ifelse(x==0, sample(x[x!=0], size=.N, replace=TRUE), x)}),
by=species]
注意你的代码
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
正在从 TRUE
和 FALSE
的值中采样,因为您没有使用此逻辑运算 ir$Sepal.Width != 0
进行子集化 - 您需要
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width[ir$Sepal.Width != 0]), ir$Sepal.Width)
我想使用 sample
替换我的数据集中的 0 以在列中随机 select 一个值来替换它。
我有这个示例数据集:
Sepal.Length Sepal.Width Petal.Length Petal.Width species
1 0.0 3.5 0.0 0.2 setosa
2 4.9 3.0 0.0 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.0 setosa
5 5.0 0.0 0.0 0.0 setosa
6 0.0 0.0 0.0 0.4 setosa
我试过:
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
[1] 3.5 3.0 3.2 3.1 0.0 0.0 3.4 1.0 2.9 1.0 3.7 1.0 3.0 3.0 4.0
零仍然存在。我尝试对所有列进行循环,因为对每一列执行上面的代码太耗时了,我已经尝试过:
lapply(ir[,-5], function(x)ifelse(ir[,1:4] == 0, sample(ir[,1:4]),ir[,1:4]))
然而,它会创建不必要的数据列,并且仍然保留零。
可重现代码:
structure(list(Sepal.Length = c(0, 4.9, 4.7, 4.6, 5, 0, 4.6,
5, 4.4, 0, 5.4, 4.8, 0, 0, 0), Sepal.Width = c(3.5, 3, 3.2, 3.1,
0, 0, 3.4, 0, 2.9, 0, 3.7, 0, 3, 3, 4), Petal.Length = c(0, 0,
1.3, 1.5, 0, 0, 1.4, 1.5, 1.4, 1.5, 0, 1.6, 1.4, 1.1, 1.2), Petal.Width = c(0.2,
0.2, 0.2, 0, 0, 0.4, 0.3, 0.2, 0.2, 0, 0.2, 0, 0, 0, 0.2), species = structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("setosa",
"versicolor", "virginica"), class = "factor")), row.names = c(NA,
15L), class = "data.frame")
用向量中的随机非零值替换零的函数:
f <- function(vec){
ind <- vec == 0
vec[ind] <- sample(vec[!ind], sum(ind), TRUE)
vec
}
将函数 f
应用于每个数字列:
library(data.table)
num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
setDT(df)[, (num_cols) := lapply(.SD, f), .SD = num_cols]
或使用基数 R
num_cols <- names(df)[as.vector(lapply(df, class)) == "numeric"]
df[num_cols] <- lapply(df[num_cols], f)
注
最好使用 Advanced R 书中的 sample
函数:
sample <- function(x, size = NULL, replace = FALSE, prob = NULL) {
size <- size %||% length(x)
x[sample.int(length(x), size, replace = replace, prob = prob)]
}
因为 base::sample
在 x
是长度为 1 的数字的情况下的行为。
这是一个简短的 dplyr
解决方案:
ir %>%
mutate(across(.cols = where(is.numeric),
~ replace(., . == 0, sample(.[. != 0], length(.[. == 0]), replace=T))))
您可能需要也可能不需要 replace=T
,它允许重复采样元素。
使用 data.table (library(data.table)
):
setDT(ir)
ir[, Sepal.Width :=
ifelse(Sepal.Width==0,
sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE),
Sepal.Width),
by=species]
您也可以通过添加 by
setDT(ir)
ir[, Sepal.Width :=
ifelse(Sepal.Width==0,
sample(Sepal.Width[Sepal.Width!=0], .N, replace=TRUE),
Sepal.Width),
by=species]
为所有课程获取此信息:
ir[, c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width") :=
lapply(.SD, function(x) {
ifelse(x==0, sample(x[x!=0], size=.N, replace=TRUE), x)}),
by=species]
注意你的代码
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width != 0), ir$Sepal.Width)
正在从 TRUE
和 FALSE
的值中采样,因为您没有使用此逻辑运算 ir$Sepal.Width != 0
进行子集化 - 您需要
ifelse(ir$Sepal.Width == 0, sample(ir$Sepal.Width[ir$Sepal.Width != 0]), ir$Sepal.Width)