本节书摘来自华章计算机《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一书中的第2章,第2.8节,作者:[美] 德博拉·诺兰(Deborah Nolan)  邓肯·坦普·朗(Duncan Temple Lang) 

2.8 练习题

Q.1 使用read.fwf()写一个函数将MenTxt/和WomenTxt/中的28个文本表读取到R中。这些文本表的名称为1999.txt、2000.txt,等等,在2.2节中对它们有非常详细的介绍。使用纯文本编辑器检查这些表格,以确定表中每一列(姓名,居住地,年龄,比赛时间和净时间)的开始和结束位置。使用统计方法探索比赛结果并确保从文本的正确位置提取信息。
Q.2 修改extractVariables()函数(参见2.2节),去除menTables中的空白行。除此之外,消除以‘*’或者‘#’开头的行。你会发现下面的正则表达式有助于定位到表中的空白行:

该模式使用了几个元字符。“^”锚定字符串的开始位置,“$”锚定字符串的结尾,“[[:blank:]]”表示任意空格符或Tab符的等价类,“”表示空格符可以出现0次或多次。整个表达式“^[[:blank:]]$”表示能够匹配从开头到结尾含有任意个空格符的字符串。
Q.3 查找时间仅为1.5的记录,看发生了什么?确定如何处理该问题以及哪个函数需要被修改,是extractResTable()、extractVariables()还是cleanUp()。在你的修改中,应该包括一条提供警告消息的代码,该警告提示哪些行是因为时间太短而被舍弃的。
Q.4 检查2006年男选手数据的头部和尾部。观察menResMat列表中的字符矩阵和menFiles列表中的字符向量(见2.2节)。(回想一下,我们期望的menResMat中的字符矩阵和menFiles中的字符向量都对应于名为"2006"的元素)。查看居住地有什么错误?仔细检查头部找出错误是怎么发生的。修改extractVariables()函数来解决这个问题。
Q.5 实现2.3节中所述的convertTime()函数。这个函数输入的字符串时间格式是hh:mm:ss或mm:ss,返回值是与时间对应的数值型的分钟数。设计该函数,以便输入包含多个字符串的字符向量,并返回一个数值型向量。
Q.6 修改2.3节中的createDF()函数解决2006年男选手文件的格式转换问题。为了确定问题所在,你需要仔细地检查原始的文本文件。
Q.7 按照第2.2节所述的方法读取女选手文件,然后使用2.3节中的函数处理这些数据,创建数据框以便进行数据分析。你可能需要泛化createDF()和extractVariables()函数,以处理原文本文件中额外的异常情况。
Q.8 修改创建图2-6的plot()函数调用以创建图2-7。为此,你需要阅读plot()函数的文档以确定哪个参数是有用的,也就是,?plot.default包含的有关常用绘图参数的有用信息。
Q.9 修改2.4.2节中的分段线性拟合,在70岁处添加一个拐点。检查拟合系数并比较拟合曲线和loess曲线。额外的拐点可以提高拟合度吗?分段的线性模型更接近loess曲线吗?
Q.10 我们看到1999年的参赛选手普遍比2012年的选手年长。使用分位数-分位数图、箱线图和密度曲线,来比较全部14年来参赛者的年龄分布。年龄分布是如何随着年份改变的?它是渐进变化的吗?
Q.11 使用同龄人的最快跑步时间来标准化每位男选手的跑步时间。为此,需要找到20~80岁每个年龄中跑步最快的选手,这里使用tapply()函数可能有帮助。使用loess()函数平滑时间,并用predict()函数找出平滑后的时间值。使用这些平滑后的最快时间去标准化每一个跑步时间。用密度曲线、分位数-分位数图和概要统计数据对1999年和2012年参赛者的“年龄-标准化时间”分布进行比较。你会发现什么?对女选手重复以上过程。将女选手在1999年和2012年的分布以及男选手在1999年和2012年的分布进行比较。
Q.12 清洗menRes里home中的字符串,移除全部的首尾空白符和多个连续的空格。同时将所有的字母变为小写,从字符串中移除所有的标点符号,如“.”、“,”或“’”。将清洗后的home版本存放到menRes中,并命名为homeClean。
Q.13 在2.5节中我们通过将名字、出生年月、州名组合在一起为每位参赛选手创建了一个id。考虑使用居住地代替州名,这样对匹配会有什么影响?有多少参赛者使用这个新的id参加了至少8场比赛?如果你将比赛次数减少为6场呢?在匹配过程中应该使用该额外限制吗?
Q.14 在纵向分析中,通过舍弃那些在连续比赛场次中时间间隔较大和没有完成两次或两次以上比赛的选手ID,来进一步提炼运动员集合(见2.5节)。当你添加这些额外限制后还有多少唯一的ID?2.6节中的纵向分析结果发生变化了吗?
Q.15 按照2.5节中编写的程序,清洗女选手的姓名和居住地,并为女选手创建纵向记录。然后按照2.6节中的建模方法,研究参加了多场比赛的女选手的年龄和比赛用时之间的关系。
Q.16 考虑在纵向分析中采用非参数曲线拟合方法。Rice[4]建议将平均曲线和个体曲线组合起来,对个体行为建模。也就是说,个体水平的预测是平均曲线和个体曲线之和:Yi(t)=(t) + fi(t) + ∈,其中Yi(t)是个体i在年龄t时的水平。他建议采用“两步”处理过程来进行:(a)对所有个体的平滑曲线取一个鲁棒性强的平均值;(b)在个体数据点中减去平均平滑曲线值,并平滑残差。
Rice同时还建议在生成个体曲线的过程中,要在最近邻的时间集上进行平滑,而不是只用个体的跑步时间去生成个体的曲线。此处的最近邻指的是年龄和跑步时间都比较接近的一个选手。
Q.17 在2.7节中,我们发现2000个男选手结果的HTML文件格式非常差以致无法利用htmlParse()函数修复文件以从



标签中提取文本表。在本练习中,通过编写程序编辑HTML文件以便可以正常使用htmlParse()函数。为此,首先要使用readLines()函数从站点http://www.cherryblossom.org/cb003m.htm读取HTML文件。仔细检查第2.7节中显示的HTML,然后设法纠正它。考虑是否需要删除



标签中便会包含文本表,这样你就可以将纠正后的HTML传递给htmlParse()函数。你可能需要用文本连接来做这项工作,而不是将它写入磁盘然后再读取它。
Q.18 修订2.7节中的extractResTable()函数,使之能够读取2009年男选手的比赛结果。仔细检查原始的HTML文件,以确定如何找到参赛选手的信息。使用XPath定位



标签,并抽取文本值。2009年女选手的比赛结果不需要这种特殊处理。修改extractResTable()函数,以确定是否要对



标签执行特殊处理。
Q.19 修订2.7节中的extractResTable()的函数,使之接受一个额外参数file。设置file参数的缺省值为NULL。当参数file为NULL时,解析结果以字符向量的方式从extractResTable()函数中返回;如果不是NULL值,那么将结果写入file命名的文件中。这里使用writeLines()函数可能会有所帮助。
参考文献