在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
本节书摘来自华章计算机《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一书中的第2章,第2.3节,作者:[美] 德博拉·诺兰(Deborah Nolan) 邓肯·坦普·朗(Duncan Temple Lang) 更多章节内容可以访问云栖社区“华章计算机”公众号查看。 2.3 数据清洗和变量格式化本节我们考虑如何将特征矩阵列表menResMat转换为合适的格式以便于数据分析。目前,这些数据值都是字符型,这对于诸如找到参赛者年龄的中位数这样的数据分析是无益的。但是,我们可以利用as.numeric()函数很容易地将年龄转换为数值型。我们需要将整个矩阵都转换为数值型矩阵吗?事实并非如此,比如将参赛者的名字转换为数值型就毫无意义。为此,我们需要创建一个可以允许拥有不同类型变量的数据框。现在我们有6个变量:参赛者姓名、居住地、年龄以及3种类型的时间。正如刚才所说,我们将年龄转换为数值型,而名字依然保留为字符型。那么其他的变量呢?我们或许也要将居住地保留为字符型。 我们收到了一条警告信息,提示在将年龄从字符型转化到数值型的过程中出现了NA值,这意味着一些值并不对应相应的数字。要想进一步探究出现这些信息的具体原因,首先我们要检查age。 图2-4揭示了其中2个年份数据中的问题。2003年中所有参赛选手的年龄均小于10,而2006年超过1/4的参赛选手的年龄小于10,显然这是有问题的。 图2-4 历年年龄数据的箱线图。这些并排的年龄箱线图表明2003年和2006年的数据存在一些问题。这几年的参赛选手异乎寻常地年轻 我们注意到在2003年中,年龄值列相较于它对应的‘=’字符向右偏移了一位,这就意味着我们只取了年龄值中十位上的数字。而在2006年,某些行(并不是所有行)的年龄值向外溢出了一个字符。 当我们在selectCols()函数中使用这个修改计算后,每个字段后的空白字符将会被包含进来。而这并不影响我们将文本数据转换为数值型,而且如果不想让字符型变量以空白符结尾,我们也可以通过正则表达式很容易地移除这些空白字符。 图2-5 历年年龄数据的箱线图。这些并排的年龄箱线图显示了一个合理的年龄分布。例如,所有年度年龄范围的下四分位数都在29到32之间。之前发现的2003年和2006年的数据问题已被解决 下面我们来检查与向量age2001中某个NA值对应的原始文件中的行。回想一下,我们在抽取变量值之前舍弃了原始文件的头部,因此,为了能够从原始数据表中读取到正确的行,我们需要给age2001中NA所在行的位置加上一个偏移量。采用如下方法确定偏移量: 然后我们采用下列方法,找到在原始文件中年龄值为坏数据的行: 除了最后一行外,其余的行全部为空串。最后一行对应的是脚注,它定义了“#”标识符的含义。那么这些空白行在表格中又处于什么位置呢? 可见这些空白行分散在文件中的各个位置。我们可以在数据抽取过程中使用正则表达式检测这些空白行并把它们移除。 上述表达式将定位所有只包含空格的行。grep的第一个参数采用几个元字符指定我们将要匹配的字符串模式。其中,“^”锚定字符串的开始位置,“$”锚定字符串的结尾,“[[:blank:]]”指代的是空格符或Tab符的等价类,“”表示空格符可以出现0次或多次。整个表达式“^[[:blank:]]$”表示能够匹配从开头到结尾含有任意个空格符的字符串。也就是只含有空格字符的行。 显然有许多参赛选手的年龄输入为0!鉴于这些都是表中的实际值,我们在后面分析数据时,可以根据需要来决定如何处理这些选手的数据。至此,我们已经成功地创建了年龄变量。然而,由于一个变量基于位置上的错误往往会导致在其他变量上产生错误,一般我们需要对所有变量同时进行清洗。这样,在清洗其他变量时,我们可能也需要再次检查年龄数据,以确保年龄值仍然有效。 处理过程中字符串中的“:”将被舍弃,从strsplit()函数返回的是一个字符向量列表。每个输入的时间字符串对应一个向量,向量中的元素为时间字符串中被每个“:”分开的片段。我们通过检查第一个和最后一个时间来确认分割是否正确,即 显然我们的时间转换是正确的。在前面我们看到2012年最快的参赛选手完成比赛用时为45分15秒,也就是45.25分钟;最慢的参赛者用时为2小时30分钟59秒,也就是将近151分钟。在此我们留一练习:将该转换过程封装到名为convertTime()的函数中。 将这个新函数createDF(),应用于所有男选手的结果数据,如下: 对收到的警告消息进行检查: 以上警告中提示的转换问题很可能来自于将时间由字符串转换成分钟数的转换过程中,因为前面我们已经处理了年龄的转换问题。下面检查runTime中出现的NA值的个数: 可以看到在2007年、2009年和2010年出现了大量的NA,并且显示在2006年数据中所有跑步时间的值都是NA。 我们可以简单通过修改createDF()函数来消除时间信息中带有的脚注符(“#”和“*”),并去掉那些没有完成比赛的选手记录。函数修正如下: 当我们将修改后的函数应用于menResMat以创建数据框后,除了2006年的数据之外,其余年份中所有在时间上的缺失值都消失了。 对2006年文件的头部进行仔细观察,我们便可发现问题所在,但是为了内容简洁,我们还是将此问题留作练习。 do.call()函数让我们很方便地将列表中的元素作为单个参量传入一个函数中。例如,rbind()函数的第一个参量是“…”,即 “…”参量表示允许调用者向此函数传入任意数量的参量,就rbind()函数而言,这些传入的参量被合并成为一个对象。我们也可以使用以下方法调用rbind()函数: 但这样的话就有些繁琐,并且需要提前知道menDF包含14个数据框。使用do.call()函数,可以将这些输入作为一个列表提供给rbind()函数作为参量,然后do.call()为我们一起调用rbind()函数。 另外,我们对cbMen中变量的概要进行检查,查看是否还有问题出现,如在将各个数据框强制绑定到一起时可能产生的问题。 |
请发表评论