手把手教你用R处理常见的数据清洗问题(附步骤解析、R语言代码)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

R是进行运算、清洗、汇总及生成概率统计等数据处理的一个绝佳选择。此外,由于它独立于平台、短期内不会消失,所以生成的程序可以在任何地方运行。并且,它具备非常棒的辅助资源。

本文摘录自James D.Miller撰写的《数据科学统计学》(Statistics for Data Science)一书,该书由Packt Publishing出版。

R是一种易上手的语言和环境,它本身很灵活且专注于统计计算,因此成为运算、清洗、汇总及生成概率统计等数据处理的一个绝佳选择。

此外,以下是用R进行数据清洗的其他原因:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 由于大量数据科学家都在使用R,所以它短时间内不会消失。
d47e62d2b349aca45e42305ed6714efbe5ed61d9 R独立于平台,因此可以在任意地方运行程序。
d47e62d2b349aca45e42305ed6714efbe5ed61d9 R有绝佳的辅助资源---Google一下,你就可以看到。

注:尽管作者将示例数据命名为“赌博数据”(Gamming Data),它只是用来演示代码的赌博数据。

离群点

对离群点最简单的解释是:离群点是和其余数据不匹配的数据点。按照惯例,任何过高、过低或者异常(基于项目背景)的数据都是离群点。作为数据清洗的一部分,数据科学家通常要识别出离群点并用通用的方法解决它:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 删除离群点的值,甚至是离群点对应的实际变量。
d47e62d2b349aca45e42305ed6714efbe5ed61d9 转换变量值或变量本身。

让我们来看一下实际案例中如何用R识别并解决数据离群点。

老虎机在赌博界十分流行(老虎机的操作方法是把硬币投入到机器中,并拉动把手来决定回报)。如今大部分老虎机都电子化了,编程使它们的所有活动都能被持续追踪。在本文的案例中,赌场的投资者希望利用这些数据(以及各种补充数据)来调整盈利策略。换句话说,什么能让老虎机赚更多钱?是机器的主题还是类型?新机器比旧机器或老式机器更有利可图吗?机器的位置会产生怎样的影响?低面额的机器会赚更多钱吗?我们尝试用离群点来找到答案。

给定一个集合或赌博数据库(格式为逗号分隔或CSV文本文件),其中包括的数据如老虎机的位置、钱的面额、月份、日、年、机器类型、机器的年龄、促销、优惠券、天气和投币量(投币量是放入机器的钱币总额减去支付的数额)。

作为一个数据科学家,第一步要对数据进行综评(有时称为概述),此时我们要确定是否存在异常值,第二步是解决这些离群点。

步骤一 数据概述

R使这一步骤变得非常简单。尽管可以通过很多方式编程求解,但我们要尝试用最少的程序代码或脚本来解决问题。将CSV文件定义为R的变量(命名为MyFile)并将文件读入为数据框(命名为Mydata):

MyFile<-"C:/GammingData/SlotsResults.csv"

MyData<- read.csv(file=MyFile, header=TRUE, sep=",")

在统计学上,箱型图是一种简单的方式以得到统计数据集的分布、变异性和中心(或中位数)相关信息,所以我们将用箱型图来研究我们能否识别出中位数Coin-in以及能否找到离群点。为了达成这些,我们可以让R画出文件中每个老虎机的Coin-in值,绘制箱型图的函数如下:

boxplot(MyData[11],main='GammingData Review', ylab = "Coin-in")

注:Coin-in是文件中的第11列,所以直接将它作为boxplot函数的参数。此外还添加了一个可选择的参数(再次强调,本文已尽量保持代码的简洁度),以便在可视化图中添加标题。

执行前文的代码可以得到下图效果,包括中位数(中位数在箱型图中是中间横穿的线)以及四个离群点:

d4c23d3728c3b45dd15ee9005e7fa180416ce12a

步骤2-处理离群点

现在我们发现数据中确实存在离群点,我们要解决这些点以保证它们不会对本研究产生负面影响。首先,我们知道Coin-in有负值是不合理的,因为机器输出的钱币一定不会比投入到机器中的硬币多。基于这个原则,我们可以从文件中删除Coin-in为负值的记录。此外,R可以帮助我们用subset生成一个新的数据框,新数据集中只有Coin-in中的非负值。

我们要将subset数据框命名为noNegs:

noNegs<- subset(MyData, MyData[11]>0)

接下来,我们要再一次画图以确定已经删除负值离群点:

boxplot(noNegs[11],main='GammingData Review', ylab = "Coin-in")

这就产生了新的箱型图,如下图中所示:

947062330927ce335ea2353853b9b8a59c0a7dcc

我们可以用同样的方法去除Coin-in中极端的正值(大于1500美元)得到另一个数据子集并再次画图:

noOutliers<-subset(noNegs, noNegs[11]<1500)

boxplot(noOutliers[11],main='GammingData Review', ylab = "Coin-in")

当你对数据进行不同的迭代后,建议你保存大部分版本的数据(如果不是最重要的)。你可以用write.csv这个R函数:

write.csv(noOutliers,file="C:/GammingData/MyData_lessOutliers.csv")

注:大部分数据科学家在整个项目中采取通用的命名规律。文件的名字应该尽可能清晰以便今后帮助你节省时间。此外,特别是在处理大量数据时,你需要注意内存空间的问题。

以上代码的输出结果如下:

b484ce69772e0934d405d5c42d567c15da919795

领域知识

接下来,另一个数据清洗的技术是基于领域知识清理数据。这并不复杂,这种技术的关键是使用数据中无法察觉的信息。例如,当我们知道Coin-in不可能有负值时,我们排除了Coin-in负值的情况。另一个案例是飓风Sandy袭击美国东北部的时间。在这段时间内,机器的Coin-in值都很低(非零)。数据科学家应该基于信息判断是否要移除某段特定时期内的数据。

有效性检查

交叉验证是一种帮助数据科学家在数据库中使用规则的技术。

注:有效性检查是统计数据清洗中最普遍的形式,并且是数据开发者和数据科学家都非常熟悉的流程。

数据清洗时可以设定任意数量的有效性原则,这些原则要遵循数据科学家的意图或目标。例如有如下原则:数据类型(例如,某个字段一定要是数值型),范围限制(数据或日期要在一个特定范围内),要求(某个字段不能为空或没有值),唯一性(一个字段,或字段的结合,一定是数据库中唯一的),组成员(这个值一定是列表中的值),外键(案例中一定要被定义的明确的值或满足特殊规则),正则表达式模式(简单地说就是这个值的格式满足预设的格式),交叉字段验证(案例中的字段组合要满足特定标准)。

按照前文提到的内容,我们来看一些案例,从数据类型开始(也称为强制原则)。R提供的六个强制函数如下:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.numeric
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.integer
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.character
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.logical
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.factor
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.ordered
d47e62d2b349aca45e42305ed6714efbe5ed61d9 as.Date

这些函数,结合一些R的知识,使得在数据库中转换数据变得简单。例如,以前文的赌博数据为例,我们可以生成新的赌博结果文件,其中年龄值被存为字符型(或文本值)。为清理它,我们需要将其转化为数据型。我们可以运用以下R代码完成快速转化:

noOutliers["Age"]<-as.numeric(noOutliers["Age"])

一个需要注意的地方:用这种简单方法时,如果有数据不能转化,需要将其设定为NA值。在类型转换中,最大的工作是理解需要输入什么数据以及哪些数据类型是合法的;R有很广泛的数据类型,包括标量、向量(数值型,字符型,逻辑型),矩阵,数据框及列表。

数据清洗中我们要关注的另一个领域是正则表达式。在实践中,特别是当处理的数据来源于很多渠道时,数据科学家确实面对如下问题:字段不是理想的格式(对于当下目标而言)或者字段值的格式不一致(可能会引发错误的结果)。例如日期、社会安全号码(SSN)以及手机号码。基于数据的来源,你不得不重新输入(如前文描述),但是通常情况下,你需要基于目标将数据重新定义为可以使用的模式。

注:重新输入数据是很重要的,这样R就知道将值作为目前的数据并且你可以正确使用各种R数据函数。

一个常见的案例是当数据包括形式为YYYY/MM/DD的日期数据时,你想按每周汇总的形式呈现出时间序列分析,或者其他需要日期值的操作但是可能需要重新定义日期格式,或者你需要将其变为R日期类型。所以,假定一个新的赌博文件——只有两列数据:日期和投币量,这个文件是一个老虎机每天的投币量。

新的文件记录如下截图所示:

c86cae2a838c798b8c3429c455e4e17ad6a5cab4

数据科学家可以用各种数据清洗的案例。从验证每个数据点的数据类型入手,我们可以用R函数class来验证文档的数据类型。首先(如我们在前文案例中所作),读入CSV文件存为数据框:

MyFile<-"C:/GammingData/SlotsByMachine.csv"

MyData<- read.csv(file=MyFile, header=TRUE, sep=",")

随后,我们可以使用class函数,如下图截图所示:

ca5c04fff39bdf0fc7f9f90662921ec0b90242c5

从上图中可以看到用class来显示数据类型。

MyData是用来保存赌博数据的数据框,日期Date是向量类型,投币量Coinin是一个整数。所以,数据框和整数是有意义的,但是要注意R将日期设置为向量(factor)类型。向量是分类变量,在汇总统计、绘图和回归中非常有用,但它不是非常适用日期型。为了解决这个问题,我们可以使用R函数substr和paste,如下所示:

MyData$Date<-paste(substr(MyData$Date,6,7),substr(MyData$Date,9,10), substr(MyData$Date,1,4),sep="/")

以上代码重新定义了日期字段的格式。它将数据字段值分成三部分(月、日和年)然后按照理想的顺序(/分隔符(sep))粘贴在一起,如下截图所示:

2afec0bcf099585f2c1792cc91b363422ddf1e7b

我们发现这一行脚本将日期字段转换为字符类型,最后我们可以用as.Date函数将值重设为日期(Date)类型:

7c5e49b50799040fe7dda3811337c6bbffd6010a

稍微尝试一下,就可以重新格式化来得到理想的字符串或字符数据点。

改善数据

通过改善进行数据清理是另一种常见的技术,添加相关信息、事实或数据使得数据变得完整(可能更有价值)。这些附加数据的来源可以是用数据中现有信息或从其他来源添加信息进行计算。数据科学家花费时间完善数据的原因有很多。

基于当前的目的或目标,数据科学家补充的信息可能用于参考、比较、对比或发现趋势。

典型的用例包括:

d47e62d2b349aca45e42305ed6714efbe5ed61d9 衍生事实计算
d47e62d2b349aca45e42305ed6714efbe5ed61d9 对比日历与财政年度的使用
d47e62d2b349aca45e42305ed6714efbe5ed61d9 转换时区
d47e62d2b349aca45e42305ed6714efbe5ed61d9 货币转换
d47e62d2b349aca45e42305ed6714efbe5ed61d9 添加当前和前期指标
d47e62d2b349aca45e42305ed6714efbe5ed61d9 计算价值,如每天总出货量
d47e62d2b349aca45e42305ed6714efbe5ed61d9 保持缓慢变化的维度

注:作为数据科学家,你要经常用脚本来改善数据,这个方法要比直接编辑数据文档好得多,因为这样出错的可能性更低并且可以维持原始文件的完整性。此外,建立脚本可让你将改善的过程重复应用于多个文件或收到的新版文件中,不需要重做同样的工作。

回到我们的赌博数据中,假定我们在接收老虎机的投币量文档,同时公司在美国大陆外的地方设立赌场。这些新地点正在向我们发送文件,并且数据将纳入到我们的统计分析中。我们发现这些国际文件是以当地货币计算的投币量。为了正确地对数据建模,我们要将数据转化为美元。

场景如下:

文件来源:英国

使用货币:英镑

将英镑转化为美元的公式十分简单,只要用数额乘以汇率即可。所以,在R中:

MyData$Coinin<-MyData$Coinin* 1.4

以上代码可以完成我们想要的转换;然而,数据科学家要决定那种货币将被转化(英镑)以及汇率应当是多少。这并不是什么大问题,但是我们可以尝试创建一个用户定义的函数来确定要使用的汇率,如下所示:

getRate<- function(arg){

if(arg=="GPB") {

myRate <- 1.4

}

if(arg=="CAD") {

myRate <-1.34

}

return(myRate)

}

尽管之前的代码更简单,但以上代码说明了创建逻辑的要点,以便我们今后可以重复使用:

f108e09555bf59f15338990a996719c979a5ade7

最终,为了使整个过程更完美,我们要将函数储存(在R文档中)以便将来使用:

source("C:/GammingData/CurerncyLogic.R")

随后:

MyFile<-"C:/GammingData/SlotsByMachine.csv"

MyData<- read.csv(file=MyFile, header=TRUE, sep=",")

MyData$Coin<- MyData$Coinin * getRate("CAD")

注:当然,在最理想的情况下,我们可改进函数以便在表或文件中根据国家代码查找汇率,这样汇率能够随即时价值而改变并且可以从程序中解耦数据。

数据调和

基于研究分析的整体目标,数据科学家可以通过数据调和来转换、翻译、或将数据值映射到其他理想值。最普遍的案例是性别或国家代码。例如,如果你的文档中将性别编码为0和1或M和F,你想将数据转化为一致的MALE或FEMALE。

关于国家代码,数据科学家想要绘制地区的汇总:北美、南美和欧洲,而不是分开的美国、加拿大、墨西哥、巴西、智利、英国、法国和德国。在这种情况下,将产生合计值如下:

北美=美国+加拿大+墨西哥

南美=巴西+智利

欧洲=英国+法国+德国

需要强调的是,数据科学家可能会将所有包括性别的调查文档合并在一起,称为gender.txt,但是文档中的性别编码不同(1,0,M,F,Male和Female)。如果我们尝试用R函数表,我们会看到如下可理解的结果:

4e3e9aff3c95cb783125ed0d35fe87b39f1bd4b4

如果在最理想的状态下进行可视化分析:

lbs= c("Male", "Female")

pie(table(MyData),main="Gambling by Gender")

我们看到如下截图:

4f6e02c25da1a8fcc32693d77d7bb0bd5af184ba

为了解决性别数据编码不一致的问题,我借用了前文案例中的概念并生成简单的函数来帮助我们重新编码:

setGender<- function(arg){

if(substr(arg,1,1)=="0"| toupper(substr(arg,1,1))=="M") { Gender <- "MALE" }

if(substr(arg,1,1)=="1"| toupper(substr(arg,1,1))=="F") { Gender <- "FEMALE" }

return(Gender)

}

此次,我加入了toupper函数,因此我们不必担忧大小写,并且有substr来控制长度大于一个字符的值。

注:假定参数的值是0,1,m,M,f,F,Male或Female,否则将会引发报错。

由于R将性别作为向量类型,我发现很难应用简单的函数,所以我决定生成新的R数据框来容纳调和后的数据。并且用一个循环来读入文档中的记录并将其转化为Male 或Female:

MyFile<-"C:/GammingData/Gender.txt"

MyData<- read.csv(file=MyFile, header=TRUE, sep=",")

GenderData<-data.frame(nrow(MyData))

for(iin 2:nrow(MyData))

{

x<-as.character(MyData[i,1])

GenderData[i,1] <-setGender(x)

}

现在我们将通过以下语句得到更适合的可视化结果:

lbls= c("Male", "Female")

pie(table(GenderData),labels=lbls, main="Gambling by Gender")

以上代码的输出结果如下所示:

35101591f4c30758e3e9bc461add573131c89408

标准化

大多数主流数据科学家都已经注意到在开始统计研究或分析项目之前,将数据标准化作为数据清理过程一部分的重要性。这是很重要的,如果没有标准化,量纲不同的数据点对分析的贡献会不均等。

如果你认为在0到100之间的数据点比0到1范围内的变量影响更大,你可以理解数据标准化的重要性。使用这些未经过标准化的变量,事实上在分析中赋予较大范围的变量更多的权重。为了解决这一问题并均衡这些变量,数据科学家试图将数据转化为可比的量纲。

数据点的中心化是数据标准化中最常见的例子(尽管还有很多)。为了使数据点中心化,数据科学家把文件中的每个数据点减去所有数据的平均值。

R不是做运算,它提供了scale函数,其默认方法可以通过一行代码将文件中的数值中心化或缩减。让我们来看一个简单的例子。

回到老虎机的案例中!在我们的赌博文件中,你可能还记得有一个字段叫投币量(Coinin),它是一个表示投入到机器中美元总额的值,这被看作衡量机器盈利能力的指标。这似乎是我们盈利能力分析中使用的一个重要的数据点。然而这些金额可能是误导性的,因为不同的机器有不同面额(换句话说,一些机器接受美分,而其他机器接受一角硬币或美元)。也许机器面值的差别造成了不同的量纲,我们可以使用scale函数来解决这种情况。首先,我们在下面的截图中看到,Coin.in的值:

972caca44f46582a4f966143b81422100a516772

我们可以通过以下语句对数据点Coin.in进行中心化处理:

scale(MyData[11],center = TRUE, scale = TRUE)

center的值决定了如何行中心化。center为TRUE是需要对应的行减去Coin.in均值(省略NA)。scale的值决定了如何行缩放(在中心化之后)。如果scale的值是TRUE且center值是TRUE,那么缩放是通过除以(中心化后的)Coin.in的标准差来进行的。如果center值是False,将得到均方根值。

在下图截屏中看到了差别:

723db082380ac8c720f51b987fc5d1bf6d7daf6f


原文发布时间为:2018-06-22本文作者:James D. Miller本文来自云栖社区合作伙伴“ 数据派THU”,了解相关信息可以关注“ 数据派THU”。
相关文章
|
5天前
|
开发框架 供应链 监控
并行开发模型详解:类型、步骤及其应用解析
在现代研发环境中,企业需要在有限时间内推出高质量的产品,以满足客户不断变化的需求。传统的线性开发模式往往拖慢进度,导致资源浪费和延迟交付。并行开发模型通过允许多个开发阶段同时进行,极大提高了产品开发的效率和响应能力。本文将深入解析并行开发模型,涵盖其类型、步骤及如何通过辅助工具优化团队协作和管理工作流。
|
7天前
|
机器学习/深度学习 人工智能 算法
揭开深度学习与传统机器学习的神秘面纱:从理论差异到实战代码详解两者间的选择与应用策略全面解析
【10月更文挑战第10天】本文探讨了深度学习与传统机器学习的区别,通过图像识别和语音处理等领域的应用案例,展示了深度学习在自动特征学习和处理大规模数据方面的优势。文中还提供了一个Python代码示例,使用TensorFlow构建多层感知器(MLP)并与Scikit-learn中的逻辑回归模型进行对比,进一步说明了两者的不同特点。
25 2
|
1月前
|
机器学习/深度学习 存储 人工智能
让模型评估模型:构建双代理RAG评估系统的步骤解析
在当前大语言模型(LLM)应用开发中,评估模型输出的准确性成为关键问题。本文介绍了一个基于双代理的RAG(检索增强生成)评估系统,使用生成代理和反馈代理对输出进行评估。文中详细描述了系统的构建过程,并展示了基于四种提示工程技术(ReAct、思维链、自一致性和角色提示)的不同结果。实验结果显示,ReAct和思维链技术表现相似,自一致性技术则呈现相反结果,角色提示技术最为不稳定。研究强调了多角度评估的重要性,并提供了系统实现的详细代码。
51 10
让模型评估模型:构建双代理RAG评估系统的步骤解析
|
14天前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
17 3
|
1月前
|
监控 数据挖掘 BI
项目管理流程全解析及关键步骤介绍
项目管理流程是项目成功的基石,涵盖启动、规划、执行、监控和收尾等阶段。Zoho Projects 等软件可提高效率,支持结构化启动与规划、高效执行与协作及实时监控。这些流程和工具对项目的全局视角、团队协作和风险控制至关重要。项目管理软件适用于不同规模企业,实施时间因软件复杂度和企业准备而异。
50 2
|
10天前
|
SQL 监控 关系型数据库
SQL错误代码1303解析与处理方法
在SQL编程和数据库管理中,遇到错误代码是常有的事,其中错误代码1303在不同数据库系统中可能代表不同的含义
|
10天前
|
SQL 监控 测试技术
全面解析SQL数据库迁移:步骤、挑战与最佳实践a8u.0335pw.com
随着信息技术的快速发展,数据库迁移已成为企业和组织在IT领域经常面临的一项任务。数据库迁移涉及到数据的转移、转换和适应新环境的过程,特别是在使用SQL数据库时。本文将详细介绍SQL数据库迁移的过程,探讨其面临的挑战,并分享一些最佳实践。一、数据库迁移概述数据库迁移是指将数据库从一个环境迁移到另一个环
|
14天前
|
SQL 安全 关系型数据库
SQL错误代码1303解析与解决方案:深入理解并应对权限问题
在数据库管理和开发过程中,遇到错误代码是常见的事情,每个错误代码都代表着一种特定的问题
|
1月前
|
SQL 人工智能 机器人
遇到的代码部份解析
/ 模拟后端返回的数据
15 0
|
1月前
|
设计模式 存储 算法
PHP中的设计模式:策略模式的深入解析与应用在软件开发的浩瀚海洋中,PHP以其独特的魅力和强大的功能吸引了无数开发者。作为一门历史悠久且广泛应用的编程语言,PHP不仅拥有丰富的内置函数和扩展库,还支持面向对象编程(OOP),为开发者提供了灵活而强大的工具集。在PHP的众多特性中,设计模式的应用尤为引人注目,它们如同精雕细琢的宝石,镶嵌在代码的肌理之中,让程序更加优雅、高效且易于维护。今天,我们就来深入探讨PHP中使用频率颇高的一种设计模式——策略模式。
本文旨在深入探讨PHP中的策略模式,从定义到实现,再到应用场景,全面剖析其在PHP编程中的应用价值。策略模式作为一种行为型设计模式,允许在运行时根据不同情况选择不同的算法或行为,极大地提高了代码的灵活性和可维护性。通过实例分析,本文将展示如何在PHP项目中有效利用策略模式来解决实际问题,并提升代码质量。

推荐镜像

更多