楼主: 北方Smile
1881 2

[CDA数据分析师学习之路] 如何使用R语言解决可恶的脏数据 [推广有奖]

  • 0关注
  • 3粉丝

硕士生

15%

还不是VIP/贵宾

-

威望
0
论坛币
15 个
通用积分
0
学术水平
1 点
热心指数
1 点
信用等级
1 点
经验
883 点
帖子
84
精华
0
在线时间
16 小时
注册时间
2016-3-28
最后登录
2016-4-8

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
如何使用R语言解决可恶的脏数据

[size=18.0180187225342px]在数据分析过程中最头疼的应该是如何应付脏数据,脏数据的存在将会对后期的建模、挖掘等工作造成严重的错误,所以必须谨慎的处理那些脏数据。

[size=18.0180187225342px]

[size=18.0180187225342px]脏数据的存在形式主要有如下几种情况:

[size=18.0180187225342px]

[size=18.0180187225342px]1)缺失值

[size=18.0180187225342px]2)异常值

[size=18.0180187225342px]3)数据的不一致性

[size=18.0180187225342px]下面就跟大家侃侃如何处理这些脏数据。



[size=18.0180187225342px]一、缺失值

[size=18.0180187225342px]缺失值,顾名思义就是一种数据的遗漏,根据CRM中常见的缺失值做一个汇总:

[size=18.0180187225342px]

[size=18.0180187225342px]1)会员信息缺失,如身份证号、手机号、性别、年龄等

[size=18.0180187225342px]2)消费数据缺失,如消费次数、消费金额、客单价,卡余等

[size=18.0180187225342px]3)产品信息缺失,如批次、价格、折扣、所属类别等

[size=18.0180187225342px]

[size=18.0180187225342px]根据实际的业务需求不同,可以对缺失值采用不同的处理办法,如需要给会员推送短信,而某些会员恰好手机号不存在,可以考虑剔除;如性别不知道,可以使用众数替代;如年龄未知,可以考虑用均值替换。当然还有其他处理缺失值的办法,如多重插补法。下面以一个简单的例子,来说明缺失值的处理。


[size=18.0180187225342px]#模拟一批含缺失值的数据集

[size=18.0180187225342px]set.seed(1234)

[size=18.0180187225342px]Tel <- 13812341000:13812341999

[size=18.0180187225342px]Sex <- sample(c('F','M'), size = 1000, replace = T, prob = c(0.4,0.6))

[size=18.0180187225342px]Age <- round(runif(n = 1000, min = 18, max = 60))

[size=18.0180187225342px]Freq <- round(runif(n = 1000, min = 1, max = 368))

[size=18.0180187225342px]Amount <- rnorm(n = 1000, mean = 134, sd = 10)

[size=18.0180187225342px]ATV <- runif(n = 1000, min = 23, max = 138)

[size=18.0180187225342px]df <- data.frame(Tel = Tel, Sex = Sex, Age = Age, Freq = Freq, Amount = Amount, ATV = ATV)


[size=18.0180187225342px]上面的数据框是一个不含有任何缺失值的数据集,现在我想随机产生100个缺失值,具体操作如下:


[size=18.0180187225342px]#查看原始数据集的概要

[size=18.0180187225342px]summary(df)

[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]#随机参数某行某列的下标

[size=18.0180187225342px]set.seed(1234)

[size=18.0180187225342px]i <- sample(1:6, size = 100, replace = T)

[size=18.0180187225342px]j <- sample(1:1000, size = 100)

[size=18.0180187225342px]#将下标组合成矩阵

[size=18.0180187225342px]index <- as.matrix(data.frame(j,i))

[size=18.0180187225342px]#将原始数据框转换为矩阵

[size=18.0180187225342px]df <- as.matrix(df)

[size=18.0180187225342px]#将随机参数的行列赋值为NA

[size=18.0180187225342px]df[index] <- NA

[size=18.0180187225342px]#重新将矩阵转换为数据框

[size=18.0180187225342px]df2 <- as.data.frame(df)

[size=18.0180187225342px]#变换变量类型

[size=18.0180187225342px]df2$Age <- as.integer(df2$Age)

[size=18.0180187225342px]df2$Freq <- as.integer(df2$Freq)

[size=18.0180187225342px]df2$Amount <- as.numeric(df2$Amount)

[size=18.0180187225342px]df2$ATV <- as.numeric(df2$ATV)

[size=18.0180187225342px]#再一次查看赋予缺失值后的数据框概要

[size=18.0180187225342px]summary(df2)


[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]很明显这里已经随机产生100个缺失值了,下面看看这100个缺失值的分布情况。我们使用VIM包中的aggr()函数绘制缺失值的分布情况:


[size=18.0180187225342px]library(VIM)

[size=18.0180187225342px]aggr(df2, prop = FALSE, numbers = TRUE)


[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]图中显示:Tel变量有21个缺失,Sex变量有28个缺失,Age变量有6个缺失,Freq变量有20个缺失,Amount变量有13个缺失,ATV有12个缺失。

[size=18.0180187225342px]

[size=18.0180187225342px]为了演示,下面对Tel变量缺失的观测进行剔除;对Sex变量的缺失值用众数替换;Age变量用平均值替换;Freq变量、Amount变量和ATV变量用多重插补法填充。


[size=18.0180187225342px]#剔除Tel变量的缺失观测

[size=18.0180187225342px]df3 <- df2[is.na(df2$Tel)==FALSE,]

[size=18.0180187225342px]#分别用众数和均值替换性别和年龄

[size=18.0180187225342px]#性别的众数

[size=18.0180187225342px]Sex_mode <- names(which.max(table(df3$Sex)))

[size=18.0180187225342px]#年龄的均值

[size=18.0180187225342px]Age_mean <- mean(df3$Age, na.rm = TRUE)

[size=18.0180187225342px]library(tidyr)

[size=18.0180187225342px]df3 <- replace_na(df3,replace = list(Sex = Sex_mode, Age = Age_mean))

[size=18.0180187225342px]summary(df3)


[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]这个时候,Tel变量、Sex变量和Age变量已不存在缺失值,下面对Freq变量、Amount变量和ATV变量使用多重插补法。

[size=18.0180187225342px]

[size=18.0180187225342px]可通过mice包实现多重插补法,该包可以对数值型数据和因子型数据进行插补。对于数值型数据,默认使用随机回归添补法(pmm);对二元因子数据,默认使用Logistic回归添补法(logreg);对多元因子数据,默认使用分类回归添补法(polyreg)。其他插补法,可通过?mice查看相关文档。


[size=18.0180187225342px]library(mice)

[size=18.0180187225342px]#对缺失值部分,进行5次的多重插补,这里默认使用随机回归添补法(pmm)

[size=18.0180187225342px]imp <- mice(data = df3, m = 5)

[size=18.0180187225342px]#查看一下插补的结果

[size=18.0180187225342px]imp$imp

[size=18.0180187225342px]#计算5重插补值的均值

[size=18.0180187225342px]Freq_imp <- apply(imp$imp$Freq,1,mean)

[size=18.0180187225342px]Amount_imp <- apply(imp$imp$Amount,1,mean)

[size=18.0180187225342px]ATV_imp <- apply(imp$imp$ATV,1,mean)


[size=18.0180187225342px]#并用该均值替换原来的缺失值

[size=18.0180187225342px]df3$Freq[is.na(df3$Freq)] <- Freq_imp

[size=18.0180187225342px]df3$Amount[is.na(df3$Amount)] <- Amount_imp

[size=18.0180187225342px]df3$ATV[is.na(df3$ATV)] <- ATV_imp


[size=18.0180187225342px]#再次查看填补完缺失值后的数据集和原始数据集概况

[size=18.0180187225342px]summary(df3)

[size=18.0180187225342px]summary(df2)

[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]

[size=18.0180187225342px]通过不同的方法将缺失值数据进行处理,从上图可知,通过填补后,数据的概概览情况基本与原始数据相近,说明填补过程中,基本保持了数据的总体特征。



[size=18.0180187225342px]二、异常值

[size=18.0180187225342px]异常值也是非常痛恨的一类脏数据,异常值往往会拉高或拉低数据的整体情况,为克服异常值的影响,我们需要对异常值进行处理。首先,我们需要识别出哪些值是异常值或离群点,其次如何处理这些异常值。下面仍然以案例的形式,给大家讲讲异常值的处理:

[size=18.0180187225342px]

[size=18.0180187225342px]1、识别异常值

[size=18.0180187225342px]一般通过绘制盒形图来查看哪些点是离群点,而离群点的判断标准是四分位数与四分位距为基础。即离群点超过上四分位数的1.5倍四分位距或低于下四分位数的1.5倍四分位距。

[size=18.0180187225342px]

[size=18.0180187225342px]例子:

[size=18.0180187225342px]

[size=18.0180187225342px]#随机产生一组数据

[size=18.0180187225342px]set.seed(1234)

[size=18.0180187225342px]value <- c(rnorm(100, mean = 10, sd = 3), runif(20, min = 0.01, max = 30), rf(30, df1 = 5, df2 = 20))

[size=18.0180187225342px]#绘制箱线图,并用红色的方块标注出异常值

[size=18.0180187225342px]library(ggplot2)

[size=18.0180187225342px]ggplot(data = NULL, mapping = aes(x = '', y = value)) + geom_boxplot(outlier.colour = 'red', outlier.shape = 15, width = 1.2)

[size=18.0180187225342px]

6




[size=18.0180187225342px]

[size=18.0180187225342px]转载地址:http://www.itongji.cn/cms/article/articledetails?articleid=1211


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:如何使用 R语言 处理缺失值 size 数据分析 如何

沙发
北方Smile 发表于 2016-4-7 14:46:50 |只看作者 |坛友微信交流群
图中可知,有一部分数据落在上四分位数的1.5倍四分位距之上,即异常值,下面通过编程,将异常值找出来:

#计算下四分位数、上四分位数和四分位距
QL <- quantile(value, probs = 0.25)
QU <- quantile(value, probs = 0.75)
QU_QL <- QU-QL
QL;QU;QU_QL

QQ截图20160322102827.png

2、找出异常点

which(value > QU + 1.5*QU_QL)
value[which(value > QU + 1.5*QU_QL)]

QQ截图20160322102835.png

结果显示,分别是第104、106、110、114、116、118和120这6个点。下面就要处理这些离群点,一般有两种方法,即剔除或替补。剔除很简单,但有时剔除也会给后面的分析带来错误的结果,接下来就讲讲替补。

#用离异常点最近的点替换
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

#对比替换前后的数据概览
summary(value)
summary(test01)
summary(test02)

QQ截图20160322102844.png


三、数据的不一致性

数据的不一致性一般是由于不同的数据源导致,如有些数据源的数据单位是斤,而有些数据源的数据单位为公斤;如有些数据源的数据单位是米,而有些数据源的数据单位为厘米;如两个数据源的数据没有同时更新等。对于这种不一致性可以通过数据变换轻松得到一致的数据,只有数据源的数据一致了,才可以进行统计分析或数据挖掘。由于这类问题的处理比较简单,这里就不累述具体的处理办法了。

使用道具

藤椅
pinkiez 发表于 2016-4-7 22:58:21 来自手机 |只看作者 |坛友微信交流群
马克

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-9-21 06:11