如何将随机的“NA”添加到数据框中

时间:2014-01-01 20:45:36

标签: r dataframe apply

我创建了一个带随机值的数据框

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。已经尝试了withwithin

蛮力工作:

for (i in (1:floor(n/10))) {
  df[sample(c(1:n), 1), sample(c(2:ncol(df)), 1)] <- NA
  }

但我更喜欢使用apply系列。

8 个答案:

答案 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)

查看原始缺失数据:

enter image description here

我们可以看到原始帧中没有丢失的数据。

现在应用我们的功能:

bank_nas <- add_random_nas_to_frame(bank, 5)

enter image description here

答案 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获得。