我创建了一个带随机值的数据框
n <- 50
df <- data.frame(id = seq (1:n),
age = sample(c(20:90), n, rep = TRUE),
sex = sample(c("m", "f"), n, rep = TRUE, prob = c(0.55, 0.45))
)
并想介绍一些NA
值来模拟真实世界的数据。我正在尝试使用apply
,但无法到达那里。这条线
apply(subset(df,select=-id), 2, function(x) {x[sample(c(1:n),floor(n/10))]})
会检索随机值,但
apply(subset(df,select=-id), 2, function(x) {x[sample(c(1:n),floor(n/10))]<-NA})
不会将它们设置为NA
。已经尝试了with
和within
。
蛮力工作:
for (i in (1:floor(n/10))) {
df[sample(c(1:n), 1), sample(c(2:ncol(df)), 1)] <- NA
}
但我更喜欢使用apply
系列。
答案 0 :(得分:4)
Apply返回一个数组,从而将所有列转换为相同的类型。你可以改用它:
df[,-1] <- do.call(cbind.data.frame,
lapply(df[,-1], function(x) {
x[sample(c(1:n),floor(n/10))]<-NA
x
})
)
或使用for
循环:
for (i in seq_along(df[,-1])+1) {
is.na(df[sample(seq_len(n), floor(n/10)),i]) <- TRUE
}
答案 1 :(得分:3)
在您的函数中返回x
:
> df <- apply (df, 2, function(x) {x[sample( c(1:n), floor(n/10))] <- NA; x} )
> tail(df)
id age sex
[45,] "45" "41" NA
[46,] "46" NA "f"
[47,] "47" "38" "f"
[48,] "48" "32" "f"
[49,] "49" "53" NA
[50,] "50" "74" "f"
答案 2 :(得分:2)
要在数据框中引入一定百分比的NA,可以使用以下方法:
while(sum(is.na(df) == TRUE) < (nrow(df) * ncol(df) * percentage/100)){
df[sample(nrow(df),1), sample(ncol(df),1)] <- NA
}
您还可以将“(nrow(df)* ncol(df)*百分比/ 100)”更改为固定数量的NAs
答案 3 :(得分:1)
我认为你需要从函数中返回x
值:
apply(subset(df,select=-id), 2, function(x)
{x[sample(c(1:n),floor(n/10))]<-NA; x})
但您还需要将其分配回数据框的相关子集(subset(...) <- ...
不起作用)
idCol <- names(df)=="id"
df[,!idCol] <- apply(df[,!idCol], 2, function(x)
{x[sample(1:n,floor(n/10))] <- NA; x})
(如果您只有一个非ID列,则需要df[,!idCol,drop=FALSE]
)
答案 4 :(得分:1)
只需将您的数据框传递到以下函数即可。唯一的参数是您要添加NAs的框架以及您希望与NA一起使用的要素(列)的数量。
add_random_nas_to_frame <- function(frame, num_features) {
col_order <- names(frame)
rand_cols <- sample(ncol(frame), num_features)
left_overs <- which(!names(frame) %in% names(frame[,rand_cols]))
other_frame <- frame[,left_overs]
nas_added <- data.frame(lapply(frame[,rand_cols], function(x) x[sample(c(TRUE, NA), prob = c(sample(100, 1)/100, 0.15), size = length(x), replace = TRUE)]))
final_frame <- cbind(other_frame, nas_added)
final_frame <- final_frame[,col_order]
return(final_frame)
}
例如,使用来自UCI的银行数据集的完整数据集:
https://archive.ics.uci.edu/ml/datasets/Bank+Marketing
bank <- read.table(file='path_to_data', sep =";", stringsAsFactors = F, header = T)
查看原始缺失数据:
我们可以看到原始帧中没有丢失的数据。
现在应用我们的功能:
bank_nas <- add_random_nas_to_frame(bank, 5)
答案 5 :(得分:1)
这是另一种简单的方法
您的数据框
df<-mtcars
缺少必需的数量
nbr_missing<-20
示例行和列索引
y<-data.frame(row=sample(nrow(df),size=nbr_missing,replace = T),
col=sample(ncol(df),size = nbr_missing,replace = T))
删除重复
y<-y[!duplicated(y),]
使用矩阵索引
df[as.matrix(y)]<-NA
答案 6 :(得分:1)
您还可以使用missForest软件包中的prodNA
。
library(missForest)
library(dplyr)
> bind_cols(df[1],missForest::prodNA(df[-1],noNA=0.1))
# A tibble: 50 x 3
id age sex
<int> <int> <fct>
1 1 NA m
2 2 84 NA
3 3 82 f
4 4 42 f
5 5 35 m
6 6 80 m
7 7 90 f
8 8 NA NA
9 9 89 f
10 10 42 m
# … with 40 more rows
答案 7 :(得分:0)
使用dplyr
1 ,您可以使用以下紧凑的语法来获得所需的解决方案:
set.seed(123)
library("tidyverse")
n <- 50
df <- data.frame(
id = seq (1:n),
age = sample(c(20:90), n, replace = TRUE),
sex = sample(c("m", "f"), n, replace = TRUE, prob = c(0.55, 0.45))
)
mutate(.data = as_tibble(df),
across(
.cols = all_of(c("age", "sex")),
.fns = ~ ifelse(row_number(.x) %in% sample(1:n(), size = (10 * n(
) / 100)), NA, .x)
))
每列大约用NA替换10%的值。这来自sample(1:n(), size = (10 * n() / 100))
count(.Last.value, sex)
# A tibble: 3 x 2
# sex n
# <chr> <int>
# 1 f 21
# 2 m 24
# 3 NA 5
# A tibble: 50 x 3
# id age sex
# <int> <int> <chr>
# 1 1 50 m
# 2 2 70 m
1 我正在加载tidyverse
,因为replace_na
可通过tidyr
获得。