【问题标题】:How do I add random `NA`s into a data frame如何将随机`NA`添加到数据框中
【发布时间】:2014-01-19 07:38:26
【问题描述】:

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

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 系列。

【问题讨论】:

    标签: r dataframe apply


    【解决方案1】:

    我认为您需要从函数中返回 x 值:

    apply(subset(df,select=-id), 2, function(x) 
         {x[sample(c(1:n),floor(n/10))]<-NA; x}) 
    

    但您还需要将其分配回数据框的相关子集(并且subset(...) &lt;- ... 不起作用)

    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]

    【讨论】:

    • 我注意到,通过这种方法,sex 变量被转换为chr,而在 Roland 的方法中,它仍然是 Factor(尽管存在 NA)。
    【解决方案2】:

    在你的函数中返回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"
    

    【讨论】:

    • 这也会将NA添加到id列,这是不可取的。
    • 然后将df替换为df[,c("age", "sex")]
    • 如果您使用更大维度的数据框,您会发现用df[, -1] 替换df 比列出您想要保留的所有列更容易。最后的命令应该是df[, -1] &lt;- apply (df[, -1], 2, function(x) {x[sample( c(1:n), floor(n/10))] &lt;- NA; x} )
    • @Gianluca:我的回答是这样做的(但不假设 ID 列是第一个)
    • @Ben:有趣的解决方案 Ben!我更喜欢我的,但这主要是因为我总是尝试将 ID 存储为第一列。不管怎样,谢谢你和我分享。我学到了一些新东西:)
    【解决方案3】:

    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
    }
    

    【讨论】:

    • 你不需要do.call(cbind.data.frame, ...)。你可以这样做:df[-1] &lt;- lapply(df[-1], function(x) { x[sample(c(1:n), floor(n/10))] &lt;- NA ; x })
    【解决方案4】:

    只需将您的数据框传递给以下函数。唯一的参数是您想要添加 NA 的 frame 以及您想要与 NA 一起拥有的 features(列)的数量。

    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】:

      这是另一种简单的方法

      你的数据框

      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】:

        要在数据框中引入一定百分比的 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) * percent/100)”更改为固定数量的 NA

        【讨论】:

          【解决方案7】:

          您也可以使用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
          

          【讨论】:

            【解决方案8】:

            使用dplyr1,您可以使用以下紧凑的语法获得所需的解决方案:

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

            结果

            每列大约有 10% 的值被替换为 NA。这来自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 获得。

            【讨论】:

              猜你喜欢
              • 2021-03-14
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-11-04
              • 1970-01-01
              • 1970-01-01
              • 2015-10-01
              相关资源
              最近更新 更多