将所有0值替换为 NA

我有一个数据框,里面有一些数字列。某些行的值为0,在统计分析中应视为 null。在 R 中将所有0值替换为 NULL 的最快方法是什么?

487859 次浏览

将所有零替换为 NA:

df[df == 0] <- NA



解释

1. 你应该用来替换零的不是 NULL,正如 ?'NULL'中所说,

NULL 表示 R 中的空对象

这是独一无二的,我猜,可以被看作是最没有信息和空洞的对象

data.frame(x = c(1, NULL, 2))
#   x
# 1 1
# 2 2

也就是说,R 不为这个空对象保留任何空间

NA 是一个长度为1的逻辑常数,其中包含一个缺失值 NA 可以被强制使用任何其他载体类型,原始的除外。

重要的是,NA的长度是1,因此 R 为它保留了一些空间,

data.frame(x = c(1, NA, 2))
#    x
# 1  1
# 2 NA
# 3  2

此外,数据框架结构要求所有列具有相同数量的元素,以便不存在“漏洞”(即 NULL值)。

现在,您可以在数据帧中用 NULL替换零,这意味着完全删除包含至少一个零的所有行。当使用例如 varcovcor时,这实际上等同于首先用 NA替换零并将 use的值设置为 "complete.obs"。然而,通常情况下,这并不令人满意,因为它会导致额外的信息丢失。

2.在解决方案中,我使用 df == 0向量化,而不是运行某种循环。df == 0返回(尝试一下)一个与 df大小相同的矩阵,其中包含 TRUEFALSE两个条目。此外,我们还允许将这个矩阵传递给子集 [...](参见 ?'[')。最后,虽然 df[df == 0]的结果是完全直观的,它可能似乎奇怪的 df[df == 0] <- NA提供了理想的效果。赋值操作符 <-确实并不总是那么聪明,并且不会以这种方式与其他一些对象一起工作,但是它会以这种方式与数据帧一起工作; 参见 df == 00。


集合论中的空集合似乎有某种联系。
与集合论的另一个相似之处是: 空集合是每个集合的子集,但是我们没有为它保留任何空间。

#Sample data
set.seed(1)
dat <- data.frame(x = sample(0:2, 5, TRUE), y = sample(0:2, 5, TRUE))
#-----
x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0


#replace zeros with NA
dat[dat==0] <- NA
#-----
x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

没有 [<-功能的替代方法:

一个示例数据框架 dat(厚颜无耻地抄袭@Chase 的答案) :

dat


x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

可以用 is.na<-函数用 NA代替零:

is.na(dat) <- !dat




dat


x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA

你可以只在数字字段中用 NA代替 0(也就是排除像因子这样的东西) ,但是它是以一列一列的方式工作的:

col[col == 0 & is.numeric(col)] <- NA

通过一个函数,你可以把它应用到你的整个数据框架:

changetoNA <- function(colnum,df) {
col <- df[,colnum]
if (is.numeric(col)) {  #edit: verifying column is numeric
col[col == -1 & is.numeric(col)] <- NA
}
return(col)
}
df <- data.frame(sapply(1:5, changetoNA, df))

尽管您可以用数据帧中的列数或者 1:ncol(df)来替换 1:5

让我假设 data.frame 是不同数据类型的混合,并非所有列都需要修改。

如果只修改列12到18(总共21个列中的12到18个) ,只需执行以下操作

df[, 12:18][df[, 12:18] == 0] <- NA

因为有人想要数据。由于给定的 data.frame 解决方案不适用于 data.Table,因此我将提供下面的解决方案。

基本上,使用 :=操作符—— > DT[x == 0, x := NA]

library("data.table")


status = as.data.table(occupationalStatus)


head(status, 10)
origin destination  N
1:      1           1 50
2:      2           1 16
3:      3           1 12
4:      4           1 11
5:      5           1  2
6:      6           1 12
7:      7           1  0
8:      8           1  0
9:      1           2 19
10:      2           2 40




status[N == 0, N := NA]


head(status, 10)
origin destination  N
1:      1           1 50
2:      2           1 16
3:      3           1 12
4:      4           1 11
5:      5           1  2
6:      6           1 12
7:      7           1 NA
8:      8           1 NA
9:      1           2 19
10:      2           2 40

dplyr::na_if()是一种选择:

library(dplyr)


df <- data_frame(col1 = c(1, 2, 3, 0),
col2 = c(0, 2, 3, 4),
col3 = c(1, 0, 3, 0),
col4 = c('a', 'b', 'c', 'd'))


na_if(df, 0)
# A tibble: 4 x 4
col1  col2  col3 col4
<dbl> <dbl> <dbl> <chr>
1     1    NA     1 a
2     2     2    NA b
3     3     3     3 c
4    NA     4    NA d

如果有人通过谷歌到达这里寻找 相反(即如何用0替换 data.frame 中的所有 NA) ,答案是

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

或者

使用 dplyr/tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)

如果你像我一样,在这里着陆,同时想知道如何用 NA 替换数据框架中的所有值,这只是:

df[,] <- NA

这里是我对那些使用不同类型的列和代表缺少数据的多个值的数据集的人的贡献。

dat <- data_frame(numA = c(1, 0, 3, 4),
numB = c(NA, 2, 3, 4),
strC = c("0", "1.2", "NA", "2.4"),
strD = c("Yes", "Yes", "missing", "No"))

假设在这个数据中,我们希望用 NA替换数字列中的0,以及用 NA替换字符/字符串值中的“ NA”和“丢失”值。请注意,strC列中的“ NA”是一个字符类型值,而不是所需的 NA

dat
# A tibble: 4 x 4
numA   numB  strC  strD
<dbl>  <dbl> <chr> <chr>
1     1     NA 0     Yes
2     0      2 1.2   Yes
3     3      3 'NA'  missing
4     4      4 2.4   No

首先,一个显而易见的情况是,在将字符列转换为数值时,任何非数值字符串值都被强制转换为 NA

as.numeric(dat$strC)
[1] 0.0 1.2  NA 2.4

用索引回答:

dat[dat == "NA" | dat =="missing"] <- NA

但是,不要对0使用它,因为它将数字和字符0都更改为 NA。这是因为 "0" == 0在 R 中返回 TRUE

Dplyr: : na _ if 方法:

library(dplyr)


dat %>%
lapply(na_if, y = "missing") %>%
lapply(na_if, y = "NA") %>%
lapply(na_if, y = 0) %>%  # DONT DO THIS! It converts string 0s to NA as well!
data.frame()

这里我们将 na_if函数应用于数据的每一列。由于 na_if不接受多个要转换成 NA的值,因此我们需要为每个要转换成 NA的值编写多行代码。但是,对 0的这个函数的简单使用可以将数字和字符 0转换为 NA。我们得做点别的!

使用带有 na _ if 函数的 mutate cross 方法:

这是我最喜欢的解决办法。这里我们检查列类型并根据需要应用 na_if函数。字符 0保持不变,而所有需要的值都转换为 NA

dat %>%
mutate(across(where(is.numeric), ~na_if(., 0))) %>%
mutate(across(where(is.character), ~na_if(., "NA"))) %>%
mutate(across(where(is.character), ~na_if(., "missing")))


# A tibble: 4 x 4
numA  numB strC  strD
<dbl> <dbl> <chr> <chr>
1     1    NA 0     Yes
2    NA     2 1.2   Yes
3     3     3 NA    NA
4     4     4 2.4   No

最后,可以使用 nariar

nariar是最近的一个软件包,它引入了各种 replace_with_功能。

library(naniar)

将所有“ NA”和“丢失”值替换为 NA:

dat %>%
replace_with_na_all(~.x %in% c("NA", "missing"))

但是如果在 0中使用这个值,它仍然会错误地将字符0转换为 NA:

dat %>%
replace_with_na_all(~.x %in% c(0, "NA", "missing"))


# A tibble: 4 x 4
numA  numB strC  strD
<dbl> <dbl> <chr> <chr>
1     1    NA NA    Yes
2    NA     2 1.2   Yes
3     3     3 NA    NA
4     4     4 2.4   No
#strC's first element should not be NA here!

因此,我们必须使用 place _ with _ na _ if 指定列类型:

dat %>%
replace_with_na_if(is.character, ~.x %in% c("NA", "missing")) %>%
replace_with_na_if(is.numeric, ~.x %in% c(0))


# A tibble: 4 x 4
numA  numB strC  strD
<dbl> <dbl> <chr> <chr>
1     1    NA 0     Yes
2    NA     2 1.2   Yes
3     3     3 NA    NA
4     4     4 2.4   No

我们达到了预期的结果。我希望这一切对我们有所帮助:)

另一种选择是使用 mutate_allreplaceNA一起全部为0,如下所示:

library(dplyr)
df <- data.frame(v1 = c(1,0,4,2),
v2 = c(3,1,0,0))
df
#>   v1 v2
#> 1  1  3
#> 2  0  1
#> 3  4  0
#> 4  2  0
mutate_all(df, ~replace(., .==0, NA))
#>   v1 v2
#> 1  1  3
#> 2 NA  1
#> 3  4 NA
#> 4  2 NA

Reprex 软件包于2022.07-10年度创作(v2.0.1)