【问题标题】:How to replace NA values in a table for selected columns如何为选定列替换表中的 NA 值
【发布时间】:2013-10-23 03:08:41
【问题描述】:

有很多关于替换 NA 值的帖子。我知道可以将下表/框架中的 NA 替换为以下内容:

x[is.na(x)]<-0

但是,如果我想将其限制为仅某些列怎么办?让我给你看一个例子。

首先,让我们从数据集开始。

set.seed(1234)
x <- data.frame(a=sample(c(1,2,NA), 10, replace=T),
                b=sample(c(1,2,NA), 10, replace=T), 
                c=sample(c(1:5,NA), 10, replace=T))

这给出了:

    a  b  c
1   1 NA  2
2   2  2  2
3   2  1  1
4   2 NA  1
5  NA  1  2
6   2 NA  5
7   1  1  4
8   1  1 NA
9   2  1  5
10  2  1  1

好的,所以我只想将替换限制为列“a”和“b”。我的尝试是:

x[is.na(x), 1:2]<-0

和:

x[is.na(x[1:2])]<-0

这不起作用。

我的 data.table 尝试,y&lt;-data.table(x),显然永远不会工作:

y[is.na(y[,list(a,b)]), ]

我想在 is.na 参数中传递列,但这显然行不通。

我想在 data.frame 和 data.table 中执行此操作。我的最终目标是将“a”和“b”中的 1:2 重新编码为 0:1,同时保持“c”的原样,因为它不是逻辑变量。我有一堆专栏,所以我不想一个一个地做。而且,我只是想知道如何做到这一点。

你有什么建议吗?

【问题讨论】:

    标签: r replace dataframe data.table na


    【解决方案1】:

    为了完整起见,基于@sbha 的回答,这里是具有across() 功能的tidyverse 版本,自1.0 版起在dplyr 中可用(取代*_at() 变体和其他变体):

    # random data
    set.seed(1234)
    x <- data.frame(a = sample(c(1, 2, NA), 10, replace = T),
                    b = sample(c(1, 2, NA), 10, replace = T), 
                    c = sample(c(1:5, NA), 10, replace = T))
    library(dplyr)
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    library(tidyr)
    # with the magrittr pipe
    x %>% mutate(across(1:2, ~ replace_na(.x, 0)))
    #>    a b  c
    #> 1  2 2  5
    #> 2  2 2  2
    #> 3  1 0  5
    #> 4  0 2  2
    #> 5  1 2 NA
    #> 6  1 2  3
    #> 7  2 2  4
    #> 8  2 1  4
    #> 9  0 0  3
    #> 10 2 0  1
    # with the native pipe (since R 4.1)
    x |> mutate(across(1:2, ~ replace_na(.x, 0)))
    #>    a b  c
    #> 1  2 2  5
    #> 2  2 2  2
    #> 3  1 0  5
    #> 4  0 2  2
    #> 5  1 2 NA
    #> 6  1 2  3
    #> 7  2 2  4
    #> 8  2 1  4
    #> 9  0 0  3
    #> 10 2 0  1
    

    reprex package (v2.0.1) 于 2021-12-08 创建

    【讨论】:

    • 啊,也许是因为我将它应用于 2:3 列而不是 1:2...?现已修复。
    【解决方案2】:

    这在tidyrreplace_na() 中现在是微不足道的。该函数似乎适用于 data.tables 和 data.frames:

    tidyr::replace_na(x, list(a=0, b=0))
    

    【讨论】:

      【解决方案3】:

      编辑 2020-06-15

      data.table 1.12.4(2019 年 10 月)以来,data.table 获得了两个功能来促进这一点:nafillsetnafill

      nafill 对列进行操作:

      cols = c('a', 'b')
      y[ , (cols) := lapply(.SD, nafill, fill=0), .SDcols = cols]
      

      setnafill 对表进行操作(替换通过引用/就地发生)

      setnafill(y, cols=cols, fill=0)
      # print y to show the effect
      y[]
      

      这也将比其他选项更有效;有关更多信息,请参阅 ?nafill,了解时间序列的 NA 插补的 last-observation-carried-forward (LOCF) 和 next-observation-carried-backward (NOCB) 版本。


      这适用于您的 data.table 版本:

      for (col in c("a", "b")) y[is.na(get(col)), (col) := 0]
      

      或者,正如 David Arenburg 在下面指出的那样,您可以使用 set(附带好处 - 您可以在 data.framedata.table 上使用它):

      for (col in 1:2) set(x, which(is.na(x[[col]])), col, 0)
      

      【讨论】:

      • 感谢您。只是想知道,3 年后,是否有办法在没有 for 循环的情况下完成上述操作?我想这会被 data.table 团队做得更简洁吗?谢谢。
      • @info_seekeR 我不知道更简洁的方法
      • 这是一个比 flodel 选择的答案更好的解决方案。 Flodel 的方法使用赋值运算符
      • @MichaelChirico 在评论的第一部分,您是否添加了步骤out &lt;- x 以避免对问题中的 x data.frame 产生误解?否则,这是一个更短的命令:y[, (cols):=lapply(.SD, function(i){i[is.na(i)] &lt;- 0; i}), .SDcols = cols] 跳过“out”变量名并使用“x”。
      • @MichaelChirico 真的!我完全忘记了 nafill()
      【解决方案4】:

      从data.table y开始,你可以写:
      y[, (cols):=lapply(.SD, function(i){i[is.na(i)] &lt;- 0; i}), .SDcols = cols]
      在创建 y 并运行此命令之前不要忘记 library(data.table)

      【讨论】:

        【解决方案5】:

        我们可以使用tidyr::repalce_na函数和lapplydata.table方式解决它

        library(data.table)
        library(tidyr)
        setDT(df)
        df[,c("a","b","c"):=lapply(.SD,function(x) replace_na(x,0)),.SDcols=c("a","b","c")]
        

        这样,我们也可以用NA字符串解决粘贴列。首先我们replace_na(x,""),然后我们可以使用stringr::str_c来合并列!

        【讨论】:

        • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请edit您的回答添加一些解释,包括您所做的假设。
        【解决方案6】:

        使用 {data.table} 和 {stringr} 非常方便

        library(data.table)
        library(stringr)
        
        x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]
        

        仅供参考

        【讨论】:

          【解决方案7】:

          在@Robert McDonald's tidyr::replace_na() 答案的基础上,这里有一些dplyr 选项用于控制替换NAs 的哪些列:

          library(tidyverse)
          
          # by column type:
          x %>%
            mutate_if(is.numeric, ~replace_na(., 0))
          
          # select columns defined in vars(col1, col2, ...):
          x %>%
            mutate_at(vars(a, b, c), ~replace_na(., 0))
          
          # all columns:
          x %>%
            mutate_all(~replace_na(., 0))
          

          【讨论】:

          • 使用这个函数我得到错误:Error in replace_na(., 0) : argument "value" is missing, with no default。有什么建议可以改变吗?
          【解决方案8】:

          对于特定的列,可以使用sapply 替代

          DF <- data.frame(A = letters[1:5],
                       B = letters[6:10],
                       C = c(2, 5, NA, 8, NA))
          
          DF_NEW <- sapply(seq(1, nrow(DF)),
                              function(i) ifelse(is.na(DF[i,3]) ==
                                                 TRUE,
                                                 0,
                                                 DF[i,3]))
          
          DF[,3] <- DF_NEW
          DF
          

          【讨论】:

            【解决方案9】:

            这对我来说很好用

            DataTable DT = new DataTable();
            
            DT = DT.AsEnumerable().Select(R =>
            {
                  R["Campo1"] = valor;
                  return (R);
            }).ToArray().CopyToDataTable();
            

            【讨论】:

            • 这是R吗?看起来像 C#
            【解决方案10】:

            不确定这是否更简洁,但此函数还将查找并允许替换 data.table 的选定列中的 NA(或您喜欢的任何值):

            update.mat <- function(dt, cols, criteria) {
              require(data.table)
              x <- as.data.frame(which(criteria==TRUE, arr.ind = TRUE))
              y <- as.matrix(subset(x, x$col %in% which((names(dt) %in% cols), arr.ind = TRUE)))
              y
            }
            

            应用它:

            y[update.mat(y, c("a", "b"), is.na(y))] <- 0
            

            该函数创建一个符合输入条件(在本例中为 is.na == TRUE)的选定列和行(单元格坐标)的矩阵。

            【讨论】:

              【解决方案11】:

              你可以这样做:

              x[, 1:2][is.na(x[, 1:2])] <- 0
              

              或更好(恕我直言),使用变量名:

              x[c("a", "b")][is.na(x[c("a", "b")])] <- 0
              

              在这两种情况下,1:2c("a", "b") 都可以替换为预定义的向量。

              【讨论】:

              • 就可以了。如果我想搜索“1”怎么办?我试图改变它,但我无法让它工作。
              • 大概是这样的:x[, 1:2][x[, 1:2] == 1] &lt;- 0
              • @flodel 为什么数据表x 仅在进行分配时才接受矩阵作为其第一个成员?此功能是否记录在某处?此外,我认为您忘记在第二个示例中的列名向量前加逗号。
              • @ChiseledAbs,我认为您指的是矩阵索引(例如stackoverflow.com/a/13999583/1201032),但它不仅限于赋值,还可以用于提取数据。关于缺少的逗号:不。 Data.frames 是列列表,因此如果您对[ 使用单个参数,它将提取指定的列(请参阅stackoverflow.com/a/21137524/1201032)。我希望这能回答你的问题,但在未来,请避免评论像这样的非常古老的答案;而是发布一个新问题。
              • In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector. 当我使用像 x[Vpredefined][is.na(x[Vpredefined])] &lt;- 0 这样的预定义向量时,它给了我错误
              猜你喜欢
              • 2015-10-15
              • 1970-01-01
              • 1970-01-01
              • 2011-11-08
              • 1970-01-01
              • 2019-08-23
              • 1970-01-01
              • 2017-12-19
              相关资源
              最近更新 更多