美文网首页统计分析方法R语言
R语言缺失值、异常值和重复值的识别与处理

R语言缺失值、异常值和重复值的识别与处理

作者: Hayley笔记 | 来源:发表于2021-06-07 19:44 被阅读0次

一、缺失值

1. 缺失值的识别和处理

缺失值存在的影响:无法进行求均值、求和等运算。(一般这些函数中都会有na.rm参数,设置成TRUE时可以自动去除缺失值)

x <- c(1,2,3,NA,NA,4)
x
# [1]  1  2  3 NA NA  4
sum(x)
# [1] NA
sum(x,na.rm = T)
# [1] 10
1.1 is.na函数的简单使用:

判断一个数据框中有没有缺失值,有多少缺失值

#判断有没有缺失值
is.na(x)
# [1] FALSE FALSE FALSE  TRUE  TRUE FALSE
#判断有多少缺失值(TRUE=1, FALSE=0)
sum(is.na(x))
# [1] 2
#感叹号起到取非的作用
x[!is.na(x)]
# [1] 1 2 3 4
#如果没有!就只返回NA
x[is.na(x)]
# [1] NA NA

以iris数据集为基础生成一个新的含缺失值的数据集iris_na

#在iris数据集的1-4列(数值型变量),1到最后一行中随机抽取五个值,用缺失值NA替换(i in 1:4是在1到4列中对i值做一个遍历)
iris_na <- iris
for(i in 1:4){
  iris_na[sample(1:nrow(iris),5),i]=NA
}
1.2 使用sapply函数➕which来找到这5个缺失值
# which就是一个指针函数,意思是在哪里
sapply(iris_na[,1:4],function(x)which(is.na(x)))
#      Sepal.Length Sepal.Width Petal.Length Petal.Width
# [1,]           28          12           10          19
# [2,]           54          39           20          24
# [3,]           68          76           45          26
# [4,]          132         117          119          69
# [5,]          141         128          127         143
# 每一列的缺失值的行数被显示出来 
1.3 使用psych包中的describe函数(describe函数可以极大程度的返回了数据集的基本统计值)⚠️
describe(iris_na)
#              vars   n mean   sd median trimmed  mad min max range  skew kurtosis   se
# Sepal.Length    1 145 5.83 0.82    5.8    5.80 1.04 4.3 7.7   3.4  0.26    -0.68 0.07
# Sepal.Width     2 145 3.06 0.44    3.0    3.04 0.44 2.0 4.4   2.4  0.31     0.06 0.04
# Petal.Length    3 145 3.77 1.75    4.4    3.79 1.63 1.0 6.7   5.7 -0.32    -1.40 0.15
# Petal.Width     4 145 1.21 0.76    1.3    1.20 1.04 0.1 2.5   2.4 -0.12    -1.34 0.06
# Species*        5 150 2.00 0.82    2.0    2.00 1.48 1.0 3.0   2.0  0.00    -1.52 0.07
#前四列都只返回了145个值,说明存在5个缺失值
1.4 计算缺失值的比例
sapply(iris_na[,1:4],function(x)sum(is.na(x)/nrow(iris_na)))
# Sepal.Length  Sepal.Width Petal.Length  Petal.Width 
#   0.03333333   0.03333333   0.03333333   0.03333333
# 缺失值的和/总行数
1.5 存在缺失值的回归分析
lm(Sepal.Length~Sepal.Width,data = iris_na)

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width, data = iris_na)

# Coefficients:
# (Intercept)  Sepal.Width  
#      6.4824      -0.2105 

lm(Sepal.Length~Sepal.Width,data = iris_na,na.action = na.omit)

# Call:
# lm(formula = Sepal.Length ~ Sepal.Width, data = iris_na, na.action = na.omit)

# Coefficients:
# (Intercept)  Sepal.Width  
#      6.4824      -0.2105 

na.action默认是na.omit,因此在使用lm求回归时写不写这个参数都可以。

2. 填补缺失值

❗️在进行缺失值的填补的时候一定要紧密结合数据背景和专业背景,否则易出现矫枉过正,适得其反。

2.1 简单操作系列:使用均值填补缺失值
# 求均值
mean_value <- sapply(iris_na[,1:4],mean,na.rm=TRUE)
mean_value
# Sepal.Length  Sepal.Width Petal.Length 
#     5.844138     3.064138     3.785517 
#  Petal.Width 
#     1.201379 

for(i in 1:4){
  iris_na[is.na(iris_na[,i]),i]=mean_value[i]
}
summary(iris_na)
describe(iris_na)

is.na(iris_na[,i])是在iris_na的1到4列对进行遍历,判断数据框中有没有缺失值,返回的是TRUE或FALSE。iris_na[is.na(iris_na[,I],i]就相当于根据is.na(iris_na[,i]), i的结果从iris_na中进行提取

如下方式是使用均值对所有缺失值进行填补,在缺失值存在于多个不同变量中,如肝癌,肺癌,胰腺癌等患者的术后存活时间不适合用所有数值的均值来填补,需要分类处理。

cancer <- data.frame(id=1:1000,sur_days=sample(100:1000,1000,replace = TRUE),
+                      type=sample(c('colon','liver','lung'),1000,replace = TRUE),
+                      treatment=sample(c('chemo','surg'),1000,replace = TRUE))
head(cancer)
#   id sur_days  type treatment
# 1  1      717  lung     chemo
# 2  2      699 liver     chemo
# 3  3      762 liver      surg
# 4  4      400 liver     chemo
# 5  5      599  lung     chemo
# 6  6      933  lung      surg

#生成缺失值
cancer[sample(1:1000,90),2] <- NA
mean_value <- tapply(cancer$sur_days,list(cancer$type,cancer$treatment),mean,na.rm=TRUE)
mean_value
#          chemo     surg
# colon 529.7751 550.5411
# liver 533.8811 563.5965
# lung  568.9627 517.8435

#缺失值填补
for(i in 1:3){
  for(j in 1:2){
    cancer$sur_days[is.na(cancer$sur_days)&cancer$type==rownames(mean_value)[i]
                    &cancer$treatment==colnames(mean_value)[j]]=mean_value[i,j]
  }
}

summary(cancer)
describe(cancer)
2.2 填补缺失值的高级操作

演示数据集准备

mlbench包中的BostonHousing包
library(mlbench)
data("BostonHousing")
head(BostonHousing)
#      crim zn indus chas   nox    rm  age    dis rad tax ptratio      b lstat medv
# 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98 24.0
# 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14 21.6
# 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03 34.7
# 4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94 33.4
# 5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33 36.2
# 6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21 28.7
original_data <- BostonHousing

#随机生成随机数
set.seed(2021)
BostonHousing[sample(1:nrow(BostonHousing),80),'rad'] <- NA
BostonHousing[sample(1:nrow(BostonHousing),80),'ptratio'] <- NA

对缺失值进行操作

  • 2.2.1 mice包⚠️

mice包中的md.pattern函数,可以反映数据集中缺失值情况

library(mice)
md.pattern(BostonHousing)
#     crim zn indus chas nox rm age dis tax b lstat medv rad ptratio    
# 359    1  1     1    1   1  1   1   1   1 1     1    1   1       1   0
# 67     1  1     1    1   1  1   1   1   1 1     1    1   1       0   1
# 67     1  1     1    1   1  1   1   1   1 1     1    1   0       1   1
# 13     1  1     1    1   1  1   1   1   1 1     1    1   0       0   2
#        0  0     0    0   0  0   0   0   0 0     0    0  80      80 160

0表示缺失,1表示不缺失。最下面一行是每一个变量中缺失值的总数。最下面一行显示rad和ptratio各有80个缺失,共有160个缺失。左边一列359表示359个观测都没有缺失,有67个观测rad变量缺失,ptratio没有缺失。有67个变量ptratio缺失,rad没有缺失。有13个观测red和ptratio都缺失。

对缺失值进行插补

mice_mod <- mice(BostonHousing[,!names(BostonHousing)%in% 'medv'],method = 'rf')
# rf是随机森林算法 
# BostonHousing[,!names(BostonHousing)%in% 'medv']是为了禁止medv这一列进入随机森林模型

#  iter imp variable
#   1   1  rad  ptratio
#   1   2  rad  ptratio
#   1   3  rad  ptratio
#   1   4  rad  ptratio
#   1   5  rad  ptratio
#   2   1  rad  ptratio
#   2   2  rad  ptratio
#   2   3  rad  ptratio
#   2   4  rad  ptratio
#   2   5  rad  ptratio
#   3   1  rad  ptratio
#   3   2  rad  ptratio
#   3   3  rad  ptratio
#   3   4  rad  ptratio
#   3   5  rad  ptratio
#   4   1  rad  ptratio
#   4   2  rad  ptratio
#   4   3  rad  ptratio
#   4   4  rad  ptratio
#   4   5  rad  ptratio
#   5   1  rad  ptratio
#   5   2  rad  ptratio
#   5   3  rad  ptratio
#   5   4  rad  ptratio
#   5   5  rad  ptratio

判断是否还存在缺失值
mice包中的complete()函数用于接受前面生成的模型,并生成一个完整数据。

mice_output <- complete(mice_mod)
anyNA(mice_output)
[1] FALSE
# 已经不存在缺失值了
head(mice_output)
#      crim zn indus chas   nox    rm  age    dis rad tax ptratio      b lstat
# 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    18.3 396.90  4.98
# 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14
# 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03
# 4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94
# 5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33
# 6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222    18.7 394.12  5.21

检验替换后的值和原本数据框中的值的是否一样,结果发现,预测的值80%都和未被NA替换的值一样,精度很高(高于均数、众数、中位数等等)。

predict <- mice_output[is.na(BostonHousing$rad),'rad']
actuals <- original_data$rad[is.na(BostonHousing$rad)]
mean(actuals!=predict)
# 0.2
  • 2.2.2 Hmisc
    Hmisc包的impute()函数(较粗略,不推荐)
# 使用均值进行插补
im_mean <- impute(BostonHousing$ptratio,mean) #除了mean也可以使用median等,或直接使用特定值
head(im_mean)
#         1         2         3         4         5         6 
# 18.49765*  17.80000  17.80000  18.70000  18.70000  18.70000 
# 带星号表示是插补的值

#缺失值替换
BostonHousing$ptratio <- NULL
BostonHousing$im_mean <- im_mean
  • 2.2.3VIM包⚠️
    使用本身就含有缺失值的airquality数据集进行操作
data('airquality')
head(airquality)
#   Ozone Solar.R Wind Temp Month Day
# 1    41     190  7.4   67     5   1
# 2    36     118  8.0   72     5   2
# 3    12     149 12.6   74     5   3
# 4    18     313 11.5   62     5   4
# 5    NA      NA 14.3   56     5   5
# 6    28      NA 14.9   66     5   6
# 缺失值主要集中在1-2列

采用md_pattern进行查看

md.pattern(airquality)
#     Wind Temp Month Day Solar.R Ozone   
# 111    1    1     1   1       1     1  0
# 35     1    1     1   1       1     0  1
# 5      1    1     1   1       0     1  1
# 2      1    1     1   1       0     0  2
#        0    0     0   0       7    37 44
#一共有44个缺失值

VIM的过人之处是可以使用aggr()函数对缺失值进行可视化

library(VIM)
aggr_plot <- aggr(airquality,col=c('red','green'),numbers=TRUE,sortVars=TRUE,
                  labels=names(airquality),cex.axis=0.7,gap=3)
# color定义缺失值和非缺失值的颜色
# numbers=TRUE表示显示确实值的比例
# sortVars=TRUE表示对变量按照缺失值的多少进行排序
# labels=names(airquality)定义图的标题
# cex.axis=0.7,gap=3定义坐标轴的大小和图之间的间距

#  Variables sorted by number of missings: 
#  Variable      Count
#     Ozone 0.24183007
#   Solar.R 0.04575163
#      Wind 0.00000000
#      Temp 0.00000000
#     Month 0.00000000
#       Day 0.00000000
# col是设置非缺失值和缺失值颜的参数。
# numbers=TRUE是显示缺失值和非缺失值的比例。
# sortVars=TRUE是根据缺失值的多少进行排序。
# labels是对生成的图进行标签化。
# cex.axis是定义坐标轴的大小。
绿色代表缺失,左图中左边两个变量有缺失,右边三个没有缺失。柱子的长短显示了缺失值的多少。右边的图反应缺失值的模式。Ozone单独缺失的比例是0.229,Solar.R单独缺失的比例是0.033,两个一起缺失的比例是0.013。

marginplot()是另一个对缺失值进行可视化的函数

marginplot(airquality[1:2]) #对存在缺失值的1-2列进行操作
蓝色空心点表示没有缺失,红色实心点表示缺失。紫色(37个)表示两者都缺失。图左边的盒形图,红色表示Ozone缺失时Solar.R的分布,蓝色表示不缺失时的分布,下面的盒形图红色表示Solar.R缺失时Ozone的分布,蓝色表示Solar.R不缺失时Ozone的分布。

VIM 除了进行可视化以外,还可以采取高级的方法如线性回归、KNN等来对缺失值进行插补。
如:使用线性回归法进行插补

# 使用R语言内置sleep数据集进行演示
sleepIm <- regressionImp(Sleep + Gest + Span + Dream + NonD ~ BodyWgt + BrainWgt,data = sleep)
# 使用BodyWgt和BrainWgt这两个不存在缺省的变量来对Sleep、Gest、Span、Dream和NonD这五个存在缺省的参数进行预测(线性回归的方式)和插补

插补之后

head(sleepIm)
#    BodyWgt BrainWgt       NonD      Dream Sleep     Span Gest Pred Exp Danger Sleep_imp Gest_imp Span_imp Dream_imp NonD_imp
# 1 6654.000   5712.0 -11.732867 -0.6897314   3.3 38.60000  645    3   5      3     FALSE    FALSE    FALSE      TRUE     TRUE
# 2    1.000      6.6   6.300000  2.0000000   8.3  4.50000   42    3   1      3     FALSE    FALSE    FALSE     FALSE    FALSE
# 3    3.385     44.5   8.987353  2.0132372  12.5 14.00000   60    1   1      1     FALSE    FALSE    FALSE      TRUE     TRUE
# 4    0.920      5.7   9.017324  2.0148478  16.5 15.50179   25    5   2      3     FALSE    FALSE     TRUE      TRUE     TRUE
# 5 2547.000   4603.0   2.100000  1.8000000   3.9 69.00000  624    3   5      4     FALSE    FALSE    FALSE     FALSE    FALSE
# 6   10.550    179.5   9.100000  0.7000000   9.8 27.00000  180    4   4      4     FALSE    FALSE    FALSE     FALSE    FALSE

#上面一部分显示原有缺失值已被插补,下面一部分是判断原有的值是否为缺省值,FALSE表示不是缺省值,TRUE表示是缺省值,但已经被填补。

regressionImp函数中还有个参数family,选'auto'。因为因变量包括连续型和离散型等,他们采取的回归方式是不一样的。auto模式可以自动采取合适的方法。

二、异常值

生成一个数据集

set.seed(2017)
mmhg <- sample(60:250,1000,replace = TRUE)
range(mmhg)
# [1]  60 250
min(mmhg)
# [1] 60
max(mmhg)
# [1] 250
quantile(mmhg)
#    0%   25%   50%   75%  100% 
#  60.0 106.0 153.5 198.0 250.0 
fivenum(mmhg)
# [1]  60.0 106.0 153.5 198.0 250.0

处理异常值的自定义函数

在使用时,下述代码唯一需要修改的就是var_name>230这里。在该代码中大于230被定义为极端值,可根据实际情况进行修改。

outlierHH <- function(dt,var){
  var_name <- eval(substitute(var),eval(dt))
  tot <- sum(!is.na(var_name))
  na1 <- sum(is.na(var_name))
  m1 <- mean(var_name,na.rm=T)
  par(mfrow=c(2,2),oma=c(0,0,3,0))
  boxplot(var_name,main='With outliers')
  hist(var_name,main='With outliers',xlab=NA,ylab=NA)
  outlier <- var_name[var_name>230]
  mo <- mean(outlier)
  var_name <- ifelse(var_name %in% outlier,NA,var_name)
  boxplot(var_name,main='Without outliers')
  hist(var_name,main='Without outliers',xlab=NA,ylab=NA)
  title('Outlier Check',outer = TRUE)
  na2 <- sum(is.na(var_name))
  cat('Outliers identified:',na2-na1,'\n')
  cat('Proportion (%) of outliers:',round((na2-na1)/tot*100,1),'\n')
  cat('Mean of the outliers:',round(mo,2),'\n')
  m2 <- mean(var_name,na.rm=T)
  cat('Mean without removing outliers:',round(m1,2),'\n')
  cat('Mean if we remove outliers:',round(m2,2),'\n')
  response <- readline(prompt = 'Do you want to remove outliers
                        to replace with NA?[yes/no]:')
  if(response=='y'|response=='yes'){
    dt[as.character(substitute(var))] <- invisible(var_name)
    assign(as.character(as.list(match.call())$dt),dt,envir = .GlobalEnv)
    cat('Outliers successfully removed','\n')
    return(invisible(dt))
  }else{
    cat('Nothing changed','\n')
    return(invisible(var_name))
  }
}

生成一个数据框
运行上述代码

df <- data.frame(bp=c(sample(80:250,1000,replace = T),NA,390,100))
outlierHH(df,bp)

返回了图并询问是否将大于230的值用NA替换

上:未去除异常值 下:去除异常值

三、重复值

1. 针对向量

  • 1.1unique函数(常用)
x <- c(1,2,3,4,5,1,2,3)
unique(x)
# [1] 1 2 3 4 5
  • 1.2 duplicated函数(常用)
duplicated(x)
# [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE
x[duplicated(x)]
# [1] 1 2 3
x[!duplicated(x)]
# [1] 1 2 3 4 5

2. 针对数据框

paste函数
使用paste函数,把用来判断是否存在重复值的变量贴在一起。对paste之后生成的test数据框进行判断,看它是否存在重复值就可以了。

相关文章

  • R语言缺失值、异常值和重复值的识别与处理

    一、缺失值 1. 缺失值的识别和处理 缺失值存在的影响:无法进行求均值、求和等运算。(一般这些函数中都会有na.r...

  • 数据清洗

    数据清洗:删除原始数据集中的无关数据,重复数据,平滑噪声数据,处理缺失值和异常值 缺失值的处理:删除记录 数据插补...

  • R语言之缺失值和异常值处理

    加载并查看数据基本情况 一、处理缺失值 查看NA的分布情况,有一个直观了解 根据NA的分布情况,获取数据子集 1....

  • R数据数据缺失值处理

    处理缺失值的步骤一般为: 识别缺失值 补全个案或删除个案 个案、行都是指代一个意思 识别缺失值 识别缺失值的方法很...

  • 第3章 11条数据化运营不得不知道的数据预处理经验

    目录:3.1 数据清洗:缺失值、异常值和重复值的处理3.2 将分类数据和顺序数据转化为标志变量3.3 大数据时代的...

  • 数据分析框架

    数据质量分析 一、脏数据包括: 缺失值、异常值、不一致的值、重复数据及含有特殊符号的数据。 1.缺失值处理: 删除...

  • pandas数据缺失值|异常值|重复值处理

    缺失值处理 检测异常值 检测异常值的方法:https://blog.csdn.net/qianfeng_dashu...

  • R语言缺失值处理

    {因为文章好,所以转载!!}R语言缺失值处理 2016-08-23 05:17砍柴问樵夫 数据缺失有多种原因,而大...

  • 利用R进行脏数据清洗

    在进行正式的数据分析之前,必须要保证数据的质量,故而我们要处理缺失值、异常值这些脏数据。 一、缺失值 缺失值的处理...

  • 【Python学习笔记】处理缺失值、重复值和异常值

    零、前言 刚获取的数据中可能会有一些不规整的数据,比如:缺失数据、重复数据、异常数据,因此我们需要对数据进行预处理...

网友评论

    本文标题:R语言缺失值、异常值和重复值的识别与处理

    本文链接:https://www.haomeiwen.com/subject/bznteltx.html