在进行正式的数据分析之前,必须要保证数据的质量,故而我们要处理缺失值、异常值这些脏数据。本篇博客参照了如何使用R语言解决可恶的脏数据一文,进行了模拟脏数据清洗。
一、缺失值
缺失值的处理要依据数据的类型和其内容进行相应处理,常用的方法有行删除、众数替代、均值替代以及多重插补法等等。
以下举个例子:
#生成1000条无缺失值数据 > set.seed(1234) > Tel <- 15021888000:15021888999 > Sex <- sample(c('F','M'), size = 1000, replace = T, prob = c(0.45,0.55)) > Age <- round(runif(n = 1000, min = 16, max = 60)) > Freq <- round(runif(n = 1000, min = 1, max = 368)) > Amount <- rnorm(n = 1000, mean = 134, sd = 10) > ATV <- runif(n = 1000, min = 23, max = 138) > df <- data.frame(Tel = Tel, Sex = Sex, Age = Age, Freq = Freq, Amount = Amount, ATV = ATV)
通过summary(df)得到df简单描述统计如下:
#随机产生100个缺失值 > #随机参数某行某列的下标 > set.seed(1234) > i <- sample(1:6, size = 100, replace = T) > j <- sample(1:1000, size = 100) > #将下标组合成矩阵 > index <- as.matrix(data.frame(j,i)) > #将原始数据框转换为矩阵 > df <- as.matrix(df) > #将随机参数的行列赋值为NA > df[index] <- NA > #重新将矩阵转换为数据框 > df2 <- as.data.frame(df) > #变换变量类型 > df2$Age <- as.integer(df2$Age) > df2$Freq <- as.integer(df2$Freq) > df2$Amount <- as.numeric(df2$Amount) > df2$ATV <- as.numeric(df2$ATV)
再次通过summary()函数对df2进行简单描述统计如下:
很明显,每列都随机产生了一定数量的缺失值,接下来我们来对这份数据进行清洗。
了解缺失值的分布情况,这里我们通过VIM包中的aggr()函数对缺失值分布进行可视化:
> library(colorspace) > library(grid) > library(data.table) > library(VIM) > aggr(df2,prop=FALSE,numbers=TRUE)
图中显示:Tel变量有21个缺失,Sex变量有28个缺失,Age变量有6个缺失,Freq变量有20个缺失,Amount变量有13个缺失,ATV有12个缺失。
2.针对不同的变量及其具体内容,我们对Tel变量缺失的观测进行剔除、对Sex变量的缺失值用众数替换、对Age变量用平均值替换、对(Freq变量、Amount变量和ATV变量)用多重插补法填充:
> #剔除Tel变量的缺失观测 > df3 <- df2[is.na(df2$Tel)==FALSE,] > #分别用众数和均值替换性别和年龄 > #性别的众数 > Sex_mode <- names(which.max(table(df3$Sex)))#此语句等同于Sex_mode <- df3$Sex[which.max(table(df3$Sex))] > #年龄的均值 > Age_mean <- mean(df3$Age, na.rm = TRUE) > library(tidyr) > df3 <- replace_na(df3,replace = list(Sex = Sex_mode, Age = Age_mean))
再次通过summary()函数对df3进行简单描述统计如下:
由上图可知Tel变量、Sex变量和Age变量已经不存在缺失值,接下来通过mice包对Freq变量、Amount变量和ATV变量进行多重插补。该包可以对数值型数据和因子型数据进行插补。对于数值型数据,默认使用随机回归添补法(pmm);对二元因子数据,默认使用Logistic回归添补法(logreg);对多元因子数据,默认使用分类回归添补法(polyreg)。其他插补法,可通过?mice查看相关文档。
> library(lattice) > library(mice) > imp <- mice(data = df3, m = 5) > Freq_imp <- apply(imp$imp$Freq,1,mean) > Amount_imp <- apply(imp$imp$Amount,1,mean) > ATV_imp <- apply(imp$imp$ATV,1,mean) > df3$Freq[is.na(df3$Freq)] <- Freq_imp > df3$Amount[is.na(df3$Amount)] <- Amount_imp > df3$ATV[is.na(df3$ATV)] <- ATV_imp
以上就是重复值清洗的全部过程。
二、异常值
1.识别异常值
一般我们通过四分位距来识别异常值,我们把上四分位数和下四分位数之差定义为四分卫距,把超过上四分位数1.5倍四分位距和低于下四分位数1.5倍四分位距的数据认定为异常值,举例:
> set.seed(1234) > value <- c(rnorm(100, mean = 10, sd = 3), runif(20, min = 0.01, max = 30), rf(30, df1 = 5, df2 = 20)) > #绘制箱线图,并用红色的方块标注出异常值 > library(ggplot2) > ggplot(data = NULL, mapping = aes(x = '', y = value)) + geom_boxplot(outlier.colour = 'red', outlier.shape = 15, width = 1.2)
由箱线图可知,有一部分数据落在上四分位数的1.5倍四分位距之上,即异常值,接下来我们将其找出:
> #计算下四分位数、上四分位数和四分位距 > QL <- quantile(value, probs = 0.25) > QU <- quantile(value, probs = 0.75) > QU_QL <- QU-QL > which(value > QU + 1.5*QU_QL) [1] 104 106 110 114 116 118 120 > value[which(value > QU + 1.5*QU_QL)] [1] 23.03799 21.97173 29.56914 22.74426 27.96589 21.02544 25.51085
由结果可知异常值分别为第104、106、110、114、116、118、120这7个点,处理异常值一般有两种方法,即剔除和替补,剔除很简单,重点讲讲替补:
> #用离异常点最近的点替换 > test01 <- value > out_imp01 <- max(test01[which(test01 <= QU + 1.5*QU_QL)]) > test01[which(test01 > QU + 1.5*QU_QL)] <- out_imp01 > #用上四分位数的1.5倍四分位距或下四分位数的1.5倍四分位距替换 > test02 <- value > out_imp02 <- QU + 1.5*QU_QL > test02[which(test02 > QU + 1.5*QU_QL)] <- out_imp02
以上就是异常值清理的过程。