如何为所选列替换表中的NA值


82

关于替换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尝试wherey<-data.table(x)显然永远都行不通:

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

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

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

你有什么建议吗?

Answers:


115

你可以做:

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

或更好(IMHO),请使用变量名称:

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

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


做到了。如果我要搜索“ 1”怎么办?我试图对其进行更改,但无法正常工作。
jnam27

5
大概是这样的:x[, 1:2][x[, 1:2] == 1] <- 0
flodel

@flodel为什么数据表x仅在进行分配时才接受矩阵作为其第一个成员?此功能是否记录在某处?另外,我认为您在第二个示例中忘了在带有列名称的向量前加上逗号。
ChiseledAbs

@ChiseledAbs,我认为您指的是矩阵索引(例如,参见stackoverflow.com/a/13999583/1201032),但它不仅限于赋值,它还可用于提取数据。关于缺少的逗号:不。Data.frames是列的列表,因此,如果您使用单个参数[,它将提取指定的列(请参阅stackoverflow.com/a/21137524/1201032)。我希望这能回答您的问题,但在将来,请避免评论像这样的非常老的答案;而是发布一个新问题。
flodel 2016年

In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.当我使用这样的预定义矢量时,x[Vpredefined][is.na(x[Vpredefined])] <- 0它给我带来错误
Rohit Saluja

30

编辑2020-06-15

data.table1.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时间序列插补的最后一个观测进位(LOCF)和下一个观测进位(NOCB)版本。


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

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

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

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

谢谢你 只是想知道,3年后,是否有方法可以在没有for循环的情况下进行上述操作?我想这会由data.table团队简化吗?谢谢。
info_seekeR '16

1
@info_seekeR我不知道更简洁的方式
eddi

与由flodel选择的答案相比,这是一个更好的解决方案。Flodel的方法使用赋值运算符<-,因此涉及不必要的数据复制。
迈克尔

@MichaelChirico在您的评论的第一部分,您是否添加了out <- x避免对问题的x data.frame产生误解的步骤?否则,这是一个更短的命令:y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]跳过“输出”变量名称并使用“ x”。
Yoann Pageaud

@MichaelChirico真的!我完全忘了nafill()
Yoann Pageaud

21

以@Robert McDonald的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))

1
使用此功能,我得到错误: Error in replace_na(., 0) : argument "value" is missing, with no default。有什么建议要改变吗?
Tim M. Schendzielorz,

17

现在,在tidyr中使用replace_na()变得很简单。该函数似乎适用于data.tables和data.frames:

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

2

不知道这是否更简洁,但是此函数还将在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)。


1

我们可以通过以下data.table方式解决它tidyr::repalce_na功能和lapply

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来合并列!


1
感谢您提供此代码段,它可能会提供一些有限的即时帮助。通过说明为什么这是一个很好的解决方案,正确的解释将极大地提高其长期价值,对于其他有类似问题的读者来说,这将是更加有用的。请编辑您的答案以添加一些解释,包括您所做的假设。
某些性能

0

对于特定的列,可以使用 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

0

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

library(data.table)
library(stringr)

x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]

费耶


0

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.