28. R 数据整理(三:缺失值NA 的处理方法汇总)

2021-12-17 09:21:41 浏览数 (1)

1. 获得NA 位置

可以使用is.na() 函数对向量进行遍历,如果存在NA,则会返回TRUE,反之。

代码语言:javascript复制
> is.na(c(1,2,3,NA,'sdas'))
[1] FALSE FALSE FALSE  TRUE FALSE

# 我们可以直接用which 获取TRUE 所在的index

但是,这个函数并不能很好的使用在数据框中,比如我们想要获得缺失值所在行呢?其会返回一个矩阵,对应的缺失值会在对应位置返回一个TRUE,如果这时候通过which 获取,其只会返回一个坐标,这是因为数据框经过is.na 后返回一个矩阵,而矩阵的坐标关系和向量又非常的微妙,其本质也就是向量的不同的排列,可以通过下面例子感受一下:

代码语言:javascript复制
> matrix(c(1,2,3,NA,'sdas',4),ncol=2, byrow = 2)
     [,1]   [,2]
[1,] "1"    "2" 
[2,] "3"    NA  
[3,] "sdas" "4" 
> which(is.na(matrix(c(1,2,3,NA,'sdas',4),ncol=2, byrow = 2)))
[1] 5

> matrix(c(1,2,3,NA,'sdas',4),ncol=2)
     [,1] [,2]  
[1,] "1"  NA    
[2,] "2"  "sdas"
[3,] "3"  "4"   
> which(is.na(matrix(c(1,2,3,NA,'sdas',4),ncol=2)))
[1] 4

会自动按照行来进行重组,比如矩阵:

代码语言:javascript复制
     [,1] [,2]  
[1,] "1"  NA    
[2,] "2"  "sdas"
[3,] "3"  "4" 

就相当于在1,2,3,NA... 中找了第四个NA(按照行)。

如果你是个数学鬼才,可以计算一下,也就是所在坐标对行数取余,这个余就是NA所在的行数:

代码语言:javascript复制
> which(is.na(rcmat))
[1] 205214

> 205214%p544
[1] 64126

> rcmat[64126,]
       CHROM      POS dp ad dp.1 ad.1
726209 chr19 50949779 NA  0    1    0

亦或是,你可以写个循环,对每行判断,一旦有any(存在TRUE) ,则该行存在NA值。

还有一个不错的方法,就是通过rowSums 函数,对行求和。我们都知道,布尔值实际就是0和1,我们可以利用这个特性,获得那些经过is.na 后,行和不是0 的行,那就代表其存在表示TRUE(NA)的数据了:

代码语言:javascript复制
> rcmat[!rowSums(is.na(rcmat)) == 0, ]
       CHROM      POS dp ad dp.1 ad.1
726209 chr19 50949779 NA  0    1    0

2. 去除NA

非常暴力,直接使用函数na.omit() 就可以直接对向量或者数据框操作了。会直接返回一个去除NA 所在行的新向量或数据框:

代码语言:javascript复制
> a=na.omit(c(1,2,3,NA,'sdas'))
> a
[1] "1"    "2"    "3"    "sdas"
attr(,"na.action")
[1] 4
attr(,"class")
[1] "omit"
> class(a)
[1] "character"
> as.character(a)
[1] "1"    "2"    "3"    "sdas"

3. tidyverse 中的高级函数

drop_na()

效果和na.omit 一样,但是高级之处在于,其可以指定列,对数据框某列存在NA 的行直接删除:

代码语言:javascript复制
> X[2,2] = NA;X[6,1] = NA
> X
    X1 X2
1    A  1
2    B NA
3    C  3
4    D  4
5    E  5
6 <NA>  6

很快啊~

代码语言:javascript复制
> library(tidyr)
> drop_na(X,X1)
  X1 X2
1  A  1
2  B NA
3  C  3
4  D  4
5  E  5

虽然我们也可以使用基础包做到,方法有很多啦~

代码语言:javascript复制
> X[X$X1 %in% as.character(na.omit(X$X1)),]
  X1 X2
1  A  1
2  B NA
3  C  3
4  D  4
5  E  5

replace_na()

这个函数我很喜欢,可以将指定列中的NA 替换为指定的数值:

代码语言:javascript复制
> X
    X1 X2
1    A  1
2    B NA
3    C  3
4    D  4
5    E  5
6 <NA>  6

> replace_na(X$X1,0)
[1] "A" "B" "C" "D" "E" "0"
> replace_na(X$X2,6)
[1] 1 6 3 4 5 6

fill()

不同于drop_na 的直接暴力删除,fill 非常贴心的将缺失值替换为其所在列的上一行数值的值:

代码语言:javascript复制
> fill(X,X1,X2)
  X1 X2
1  A  1
2  B  1
3  C  3
4  D  4
5  E  5
6  E  6

> X
    X1 X2
1    A  1
2    B NA
3    C  3
4    D  4
5    E  5
6 <NA>  6

函数中参数设置

很多函数,都有参数na.rm 可以直接在对列表操作时去除NA 值,比如:

代码语言:javascript复制
> a = c(3,4,NA)
> mean(a)
[1] NA  
> mean(a, na.rm = T)
[1] 3.5

0 人点赞