【问题标题】:A function to fill in a column with NA of the same type用相同类型的NA填充列的函数
【发布时间】:2019-05-12 03:54:42
【问题描述】:

我有一个包含许多不同类型列的数据框。我想用相应类的 NA 替换每一列。

例如:

df = data_frame(x = c(1,2,3), y = c("a", "b", "c"))

df[, 1:2] <- NA

生成具有两个逻辑列的数据框,而不是数字和字符。 我知道我可以告诉 R:

df[,1] = as.numeric(NA)
df[,2] = as.character(NA)

但是我如何在一个循环中对所有可能类型为 NA 的所有列集体执行此操作?

【问题讨论】:

  • 好问题 +1,但为什么这很重要?
  • 这是一个很奇怪的问题,我以后需要将数据框与另一个原始类型的框加入...
  • 但是为什么呢?请给我们更多背景信息,这似乎是毫无意义(但很有趣)的一步。
  • 我在程序开始时创建了一个数据框,有时需要根据条件获取某些列中的所有 NA。该数据框需要在程序结束时与另一个数据框连接,这可能无法获得这些 NA。为了使连接起作用,两个数据框需要具有完全相同类型的列。
  • 只是一个小修正,你不应该在这里谈论类,而是谈论原子类型,使用NA_character_NA_numeric_ 比使用as.character(NA)as.numeric(NA) 更惯用。

标签: r dplyr na


【解决方案1】:

你可以使用这个“技巧”:

df[1:nrow(df),1] <- NA
df[1:nrow(df),2] <- NA

[1:nrow(df),] 基本上告诉 R 用NA 替换列中的所有值,这样逻辑NA 在替换另一个之前被强制转换为列的原始类型价值观。

另外,如果你有很多列要替换并且 data_frame 有很多行,我建议存储行索引并重用它们:

rowIdxs <- 1:nrow(df)
df[rowIdxs ,1] <- NA
df[rowIdxs ,2] <- NA
df[rowIdxs ,3] <- NA
...

正如@RonakShah的巧妙建议,你也可以使用:

df[TRUE, 1] <- NA
df[TRUE, 2] <- NA
...

正如@Cath 所指出的,当您选择多个列时,这两种方法仍然有效,例如:

df[TRUE, 1:3] <- NA
# or
df[1:nrow(df), 1:3] <- NA

【讨论】:

  • 太棒了...如此简单:)
  • 为什么不直接df[TRUE, 1:2] &lt;- NA
【解决方案2】:

适用于 all 列的另一种解决方案是指定非 NA 并替换为 NA,即

df[!is.na(df)] <- NA

给出,

# A tibble: 3 x 2
      x    y    
  <dbl> <chr>
1    NA <NA> 
2    NA <NA> 
3    NA <NA> 

【讨论】:

    【解决方案3】:

    在保留变量类的同时一次更改所有列的另一种方法:

    df[] <- lapply(df, function(x) {type <- class(x); x <- NA; class(x) <- type; x})
    
    df
    # A tibble: 3 x 2
    #      x y    
    #  <dbl> <chr>
    #1    NA <NA> 
    #2    NA <NA> 
    #3    NA <NA> 
    

    正如@digEmAll 在 cmets 中通知的那样,还有另一种类似但更短的方法:

    df[] <- lapply(df, function(x) as(NA,class(x)))
    

    【讨论】:

    • lapply(df, function(x)as(NA,class(x))) 也应该可以工作
    • 另一个基本选项df[] &lt;- lapply(df, replace, TRUE, NA)
    • 这在很多情况下都有效,但并非总是如此。问题是某些类没有自动转换底层typeof 的方法,有时as 不知道如何处理类。用POSIXct 试试:as 会抛出错误,手动将类设置为c("POSIXt", "POSIXct") 似乎可行,但不能转换底层的NA,结果与as.POSIXct(NA) 不同
    • 最好使用typeof 而不是class,在这里它“偶然”起作用,但在一般情况下会失败(例如因素)。
    • 因为 OP 似乎是一个 tidyverse 用户,这也很合适:df &lt;- modify(df,~as(NA,typeof(.)))
    【解决方案4】:

    使用 dplyr::na_if:

    library(dplyr)
    
    df %>% 
      mutate(x = na_if(x, x),
             y = na_if(y, y))
    
    # # A tibble: 3 x 2
    #       x y    
    #   <dbl> <chr>
    # 1    NA NA   
    # 2    NA NA   
    # 3    NA NA   
    

    如果我们只想将列的子集变为NA,那么:

    # dataframe with extra column that stay unchanged
    df = data_frame(x = c(1,2,3), y = c("a", "b", "c"), z = c(4:6))
    
    df %>% 
      mutate_at(vars(x, y), funs(na_if(.,.)))
    
    # # A tibble: 3 x 3
    #       x y         z
    #   <dbl> <chr> <int>
    # 1    NA NA        4
    # 2    NA NA        5
    # 3    NA NA        6
    

    【讨论】:

    • df &lt;- mutate_all(df,~na_if(.,.))(或modify(df,~na_if(.,.)))当你在那里时:)
    • @Moody_Mudskipper 我正在使用mutate_at,因为 OP 可能希望在列的子集上执行此操作。如果他们想将此应用于所有列,那么为什么不创建一个 0 行的空数据框...
    • 我不知道... OP 的用例很模糊,但他提到用 NA 替换每一列。
    【解决方案5】:

    dplyr 使用bind_cols() 你也可以这样做:

    df <- data_frame(x = c(1,2,3), y = c("a", "b", "c"))
    classes <- sapply(df, class)
    df[,1:2] <- NA
    
    bind_cols(lapply(colnames(x), function(x){eval(parse(text=paste0("as.", classes[names(classes[x])], "(", df[,x],")")))}))
    
         V1 V2   
      <dbl> <chr>
    1    NA NA   
    2    NA NA   
    3    NA NA 
    

    请注意,这将更改列名。

    【讨论】:

      【解决方案6】:

      使用dplyr的另一种方法:

      df <- tibble(x = c(1,2,3), y = c("a", "b", "c")) 
      df
      #> # A tibble: 3 x 2
      #>       x y    
      #>   <dbl> <chr>
      #> 1     1 a    
      #> 2     2 b    
      #> 3     3 c
      
      df %>% 
        mutate(across(everything(), ~as(NA, class(.x))))
      #> # A tibble: 3 x 2
      #>       x y    
      #>   <dbl> <chr>
      #> 1    NA <NA> 
      #> 2    NA <NA> 
      #> 3    NA <NA>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-09
        • 2021-12-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多