大家好啊!这里是佳奥,休息了几天,让我们继续接下来的学习!
在篇三中我们讨论了多种数据导入R的方法,但这只是数据准备的第一步,多数需要处理的现实例子可能会面对各种形式的问题,我们来看个例子:
1 一个示例
典型问题:
1、处于管理岗位的男性和女性在听从上级的程度上是否有所不同?2、这种情况是否依国家的不同而有所不同,或者说这些由性别导致的不同是否普遍存在?
解答这些问题的一种方法是让多个国家的经理人的上司对其服从程度打分,使用的问题:
这名经理在做出人事决策之前会询问我的意见。

结果数据如下,各行数据代表了某个经理人的上司对他的评分:

每位经理人的上司根据与服从权威相关的五项陈述(q1到q5)对经理人进行评分。
例如,经理人1是一位在美国工作的32岁男性,上司对他的评价是惯于顺从,而经理人5是一位在英国工作的,年龄未知(99可能代表缺失)的女性,服从程度评分较低。
我们使用代码来创建上表格数据的数据框:

我们感兴趣的问题:
1、五个评分(q1到q5)需要组合起来,即为每位经理人生成一个平均服从程度得分。
2、在问卷调查中,被调查者经常会跳过某些问题。例如,为4号经理人打分的上司跳过了问题4和问题5。我们需要一种处理不完整数据的方法,同时也需要将99岁这样的年龄值重编码为缺失值。
3、一个数据集中也许会有数百个变量,但我们可能仅对其中的一些感兴趣。为了简化问题,我们往往希望创建一个只包含那些感兴趣变量的数据集。
4、既往研究表明,领导行为可能随经理人的年龄而改变,二者存在函数关系。要检验这种观点,我们希望将当前的年龄值重编码为类别型的年龄组(例如年轻、中年、年长)。
5、领导行为可能随时间推移而发生改变。我们可能想重点研究最近全球金融危机期间的服从行为。为了做到这一点,我们希望将研究范围限定在某一个特定时间段收集的数据上(比如,2009年1月1日到2009年12月31日)。
2 创建新变量
在典型研究项目中,创建新变量或对现有变量进行转换的方法:
变量名⬅表达式
以上语句中的“表达式”部分可以包含多种运算符和函数。下表列出了R中的算术运算符。算术运算符可用于构造公式formula。

假设有一个名为mydata的数据框,其中的变量为x1和x2,现在想创建一个新变量sumx存储以上两个变量的加和,并创建一个名为meanx的新变量存储这两个变量的均值。
使用赋值sumx <- x1 + x2将得到错误,因为R并不知道x1、x2来自数据框mydata。
那么使用sumx <- mydata$x1 + mydata$x2,语句可以执行,但只会得到独立的向量sumx,我们希望的是将两个新变量整合到原始的数据框中。下列代码可以实现:

书本作者推荐第三种,即使用函数transform( )。
3 变量的重编码
重编码涉及根据同一个变量和/或其他变量的现有值创建新值的过程。
举例来说,我们想要实现以下想法:
1、将一个连续型变量修改为一组类别值。2、将误编码的值替换为正确值。3、基于一组分数线创建一个表示及格/不及格的变量。
要实现这一功能,可以使用R的逻辑运算符。逻辑运算符表达式可返回TRUE或FALSE。见下表:

我们想将leadership数据集中经理人的连续型年龄变量age重编码为类别型变量agecat(Young、 Middle Aged、Elder)。
首先,必须将99岁的年龄值重编码为缺失值,代码:

语句variable[condition] <- expression将仅在condition的值为TRUE时执行赋值。
在指定好年龄中的缺失值后,接着使用以下代码创建agecat变量:

在leadership$agecat中写上了数据框的名称,以确保新变量能够保存到数据框中。
将中年人Middle Aged定义为55到75岁。如果一开始没把99重编码为age的缺失值,那么经理人5就将在变量agecat中被错误地赋值为“老年人”Elder。
这段代码可以写成更紧凑的:

问题还没解决。
半个小时后,,,,
问题解决了,和@陈有朴问了问,是我多加了“,”,可以直接在R里面敲回车,就可隔行运行了:

运行成功!耶!
函数within( )与函数with( )类似,不同的是它允许你修改数据框。
我们首先创建了agecat变量,并将每一行都设为缺失值。括号中剩下的语句接下来依次执行。目前agecat现在只是一个字符型变量。
但我们也可以使用许多程序包来实现变量重编码。
4 变量的重命名
如果对现在的变量名称不满意,可以使用交互的方式或者编程的方式来修改。
假设希望将变量名manager修改为managerID,并将date修改为testDate,那么可以使用语句:

调用交互式的编辑器,单击变量名,在弹出对话框修改。

以编程的方式,reshape包里有一个rename( )函数,可以用于修改变量名。
rename( )函数的使用格式为:

一个示例:

最后,通过names( )函数来重命名变量:

将重命名date为testDate,有以下代码演示:

都是异曲同工之处。
类似的方式:

将重命名q1到q5为item1到item5。
5 缺失值
在项目中,数据可能由于各种问题而出现不完整。
在R中,缺失值以符号NA(Not Available,不可用)表示。不可能出现的值(例如,被0除的结果)通过符号NaN(Not a Number,非数值)来表示。
R提供了一些函数,用于识别包含缺失值的观测。函数is.na( )允许检测缺失值是否存在。假设有一个向量:

将返回c(FALSE, FALSE, FALSE, TRUE)。
它将返回一个相同大小的对象,如果某个元素是缺失值,相应的位置将被改写为TRUE,不是缺失值的位置则为FALSE。
我们将此函数运用于先前的leadership数据集上:

这里的leadership[,6:10]将数据框限定到第6列至第10列,接下来is.na( )识别出了缺失值。
5.1 重编码某些值为缺失值
可以使用赋值语句将某些值重编码为缺失值。在我们的leadership示例中,缺失的年龄值被编码为99。在分析这一数据集之前,我们必须让R明白本例中的99表示缺失值(否则这些样本的平均年龄将会高得离谱)。
可以通过重编码这个变量完成这项工作:

任何等于99的年龄值都将被修改为NA。以确保所有的缺失数据已在分析之前被妥善地编码为缺失值,否则分析结果将失去意义。
5.2 在分析中排除缺失值
确定了缺失值的位置以后,我们需要在进一步分析数据之前以某种方式删除这些缺失值。原因是,含有缺失值的算术表达式和函数的计算结果也是缺失值。以下例子:

由于x中的第3个元素是缺失值,所以y和z也都是NA(缺失值)。
幸运的是,多数的数值函数都拥有一个na.rm=TRUE选项,可以在计算之前移除缺失值并使用剩余值进行计算:

这里计算结果:y=6
还可以通过函数na.omit( )移除所有含有缺失值的观测。na.omit( )可以删除所有含有缺失数据的行。下面是运用于我们leadership的数据集:

在结果被保存到newdata之前,,所有包含缺失数据的行均已从leadership中删除。
删除所有含有缺失数据的观测(称为行删除,listwise deletion)是处理不完整数据集的若干手段之一。
如果只有少数缺失值或者缺失值仅集中于一小部分观测中,行删除不失为解决缺失值问题的一种优秀方法。但如果缺失值遍布于数据之中,或者一小部分变量中包含大量的缺失数据,行删除可能会剔除相当比例的数据。我们将以后的学习中探索若干更为复杂精妙的缺失值处理方法。
6 日期值
日期值通常以字符串的形式输入到R中,然后转化为以数值形式存储的日期变量。
函数as.Date( )用于执行这种转化。
其语法为as.Date(x, "input_format"),其中x是字符型数据,input_format则给出了用于读入日期的适当格式,见下表:

日期的默认输入格式为yyyy-mm-dd:

将默认格式的字符型数据转化为对应日期:

则使用mm/dd/yyyy的格式读取数据。
我们的leadership数据集中,日期是以mm/dd/yyyy的格式编码为字符型变量的。
因此:

使用指定格式读取字符型变量,并将其作为一个日期变量替换到数据框中。
这种转换一旦完成,就可以使用后续各篇章中讲到的诸多分析方法对这些日期进行分析和绘图。
有两个函数对于处理时间戳数据特别实用。Sys.Date( )可以返回当天的日期,而date( )则返回当前的日期和时间。
我是6月29日编写的,所以显示日期:

使用函数format(x, format="output_format")来输出指定格式的日期值,并且可以提取日期值中的某些部分:
受一个参数(本例中是一个日期)并按某种格式输出结果(本例中使用了符号的组合)。

format( )函数可接受一个参数(本例中是一个日期)并按某种格式输出结果(本例中使用了符号的组合)。
R的内部在存储日期时,是使用自1970年1月1日以来的天数表示的,更早的日期则表示为负数。这意味着可以在日期值上执行算术运算:

显示了2000年1月1日到今天之间的天数。
最后,也可以使用函数difftime( )来计算时间间隔,并以星期、天、时、分、秒来表示。
假设我出生于1985年1月18日,我现在有多大呢?

很明显,我有1954周那么大。
6.1 将日期转换为字符型变量
我们同样可以将日期变量转换为字符型变量——虽然不太常用。
函数as.character( )可将日期值转换为字符型:

进行转换后,即可使用一系列字符处理函数处理数据(如取子集、替换、连接等)。
6.2 更进一步
要了解字符型数据转换为日期的更多细节,查看help(as.Date)和help(strftime)。
要了解更多关于日期和时间格式的知识,请参考help(ISOdatetime)。
如果你需要对日期进行复杂的计算,那么fCalendar包可能会有帮助。
7 类型转换
R中提供了一系列用来判断某个对象的数据类型和将其转换为另一种数据类型的函数。
R与其他统计编程语言有着类似的数据类型转换方式。
举例来说,向一个数值型向量中添加一个字符串会将此向量中的所有元素转换为字符型。
我们可以使用下表中列出的函数来判断数据的类型或者将其转换为指定类型:

名为is.datatype( )这样的函数返回TRUE或FALSE,而as.datatype( )这样的函数则将其参数转换为对应的类型,下面是示例:

当和下一篇中讨论的控制流(如if-then)结合使用时,is.datatype( )这样的函数将成为一类强大的工具,即允许根据数据的具体类型以不同的方式处理数据。
另外,某些R函数需要接受某个特定类型(字符型或数值型,矩阵或数据框的数据),as.datatype( )这类函数可以让我们在分析之前先行将数据转换为要求的格式。
8 数据排序
在R中,可以使用order( )函数对一个数据框进行排序。默认的排序顺序是升序。
在排序变量的前边加一个减号即可得到降序的排序结果。
以下示例使用leadership演示了数据框的排序:

9 数据集的合并
如果数据分散在多个地方,我们就需要在继续下一步之前将其合并。
本节展示了向数据框中添加列(变量)和行(观测)的方法。
9.1 添加列
要横向合并两个数据框(数据集),可以使用merge( )函数。
在多数情况下,两个数据框是通过一个或多个共有变量进行联结的(即一种内联结,inner join)。例如:

将dataframeA和dataframeB按照ID进行了合并。类似地:

将两个数据框按照ID和Country进行了合并。类似的横向联结通常用于向数据框中添加变量。
补充:
如果要直接横向合并两个矩阵或数据框,并且不需要指定一个公共索引,那么可以直接使用cbind( )函数:

这个函数将横向合并对象A和对象B。为了让它正常工作,每个对象必须拥有相同的行数,且要以相同顺序排序。
9.2 添加行
要纵向合并两个数据框(数据集),可以使用rbind( )函数:

两个数据框必须拥有相同的变量,不过它们的顺序不必一定相同。
如果dataframeA中拥有dataframeB中没有的变量,在合并它们之前做以下某种处理:1、删除dataframeA中的多余变量;2、在dataframeB中创建追加的变量并将其值设为NA(缺失)。
纵向联结通常用于向数据框中添加观测。
10 数据集子集
R拥有强大的索引特性,可以用于访问对象中的元素。也可利用这些特性对变量或观测进行选入和排除。
10.1 选入(保留)变量
从一个大数据集中选择有限数量的变量来创建一个新的数据集是常有的事。
在第2篇中,数据框中的元素是通过dataframe[row indices, column indices]这样的记号来访问的。
我们可以沿用这种方法来选择变量。例如:

从leadership数据框中选择了变量q1、q2、q3、q4和q5,并将它们保存到了数据框newdata中。将行下标留空(,)表示默认选择所有行。

实现了同样的的变量选择。
这里(引号中的)变量名充当了列的下标,因此选择的列是相同的。
最后,也可以这样:

本例使用paste( )函数创建了与上例中相同的字符型向量。
paste( )函数将在第5篇中讲解。
10.2 剔除(丢弃)变量
剔除变量的原因有很多。
举例来说,如果某个变量中有若干缺失值,我们就可能就想在进一步分析之前将其丢弃。下面是一些剔除变量的方法:

剔除变量q3和q4。
为了理解以上语句的原理,我们需要把它拆解如下:
1、names(leadership) 生成了一个包含所有变量名的字符型向量: c("managerID","testDate","country","gender","age","q1", "q2","q3","q4","q5")。
2、names(leadership) %in% c("q3", "q4") 返回了一个逻辑型向量,names(leadership)中每个 匹配q3或q4的元素的值为TRUE,反之为FALSE: c(FALSE, FALSE, FALSE, FALSE,FALSE, FALSE, FALSE, TRUE, TRUE, FALSE)。
3、运算符非(!)将逻辑值反转:c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE,FALSE, TRUE)。
4、leadership [c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE,TRUE)] 选择了逻辑值为TRUE的列,于是q3和q4被剔除了。
在知道q3和q4是第8个和第9个变量的情况下,可以使用语句:

将它们剔除。这种方式的工作原理是,在某一列的下标之前加一个减号(-)就会剔除那一列。
最后,相同的变量删除工作亦可通过:

这回我们将q3和q4两列设为了未定义(NULL)。
注意,NULL与NA(表示缺失)是不同的。
丢弃变量是保留变量的逆向操作。选择哪一种方式进行变量筛选依赖于两种方式的编码难易程度。
如果有许多变量需要丢弃,那么直接保留需要留下的变量可能更简单,反之亦然。
10.3 选入观测
选入或剔除观测(行)通常是成功的数据准备和数据分析的一个关键方面,下面是例子:

在以上每个示例中,我们只提供了行下标,并将列下标留空(故选入了所有列)。
在第一个示例中:
我们选择了第1行到第3行(前三个观测)。
在第二个示例中:
我们选择了所有30岁以上的男性。让我们拆解这行代码以便理解它:
1、逻辑比较 leadership$gender=="M" 生成了向量 c(TRUE, FALSE, FALSE, TRUE,FALSE)。
2、逻辑比较 leadership$age > 30 生成了向量 c(TRUE, TRUE, FALSE, TRUE, TRUE)。
3、逻辑比较 c(TRUE, FALSE, FALSE, TRUE, TRUE) & c(TRUE, TRUE, FALSE, TRUE,TRUE) 生成了向量 c(TRUE, FALSE, FALSE, TRUE, FALSE)。
4、函数which( )给出了向量中值为TRUE元素的下标。因此,which(c(TRUE, FALSE,FALSE, TRUE, FALSE)) 生成了向量 c(1, 4)。
5、leadership[c(1,4),] 从数据框中选择了第一个和第四个观测。这就满足了我们的选取准则(30岁以上的男性)。
第三个示例:
使用了attach()函数,所以我们就不必在变量名前加上数据框名称了。
如果我们想把研究范围限定在2009年1月1日到2009年12月31日之间收集的观测上。怎么做呢?

首先,使用格式mm/dd/yy将开始作为字符值读入的日期转换为日期值。
然后,创建开始日期和结束日期。
由于as.Date( )函数的默认格式就是yyyy-mm-dd,所以我们无须在这里提供这个参数。
最后,像上例一样选取那些满足我们期望中准则的个案即可。
10.4 subset()函数
前两节中的示例很重要,因为它们辅助描述了逻辑型向量和比较运算符在R中的解释方式。
现在不妨来看一种简便方法:
使用subset函数大概是选择变量和观测最简单的方法了。两个示例如下:

在第一个示例中,我们选择了所有age值大于等于35或age值小于24的行,保留了变量q1到q4。
在第二个示例中,我们选择了所有25岁以上的男性,并保留了变量gender到q4(gender、q4和其间所有列)。
我们在第2篇中已经看到了冒号运算符from:to。在这里,它表示了数据框中变量from到变量to包含的所有变量。
10.5 随机抽样
我们可能希望选择两份随机样本,使用其中一份样本构建预测模型,使用另一份样本验证模型的有效性。
sample( )函数能够让我们从数据集中(有放回或无放回地)抽取大小为n的一个随机样本。
可以使用以下语句从leadership数据集中随机抽取一个大小为3的样本:

sample( )函数中的第一个参数是一个由要从中抽样的元素组成的向量。
在这里,这个向量是1到数据框中观测的数量,第二个参数是要抽取的元素数量,第三个参数表示无放回抽样。
sample( )函数会返回随机抽样得到的元素,之后即可用于选择数据框中的行。
更进一步
R中拥有齐全的抽样工具,包括抽取和校正调查样本(sampling包)以及分析复杂调查数据(survey包)的工具。
11 小结
我们在本章中学习了大量的基础知识。
我们看到了R存储缺失值和日期值的方式,并探索了它们的多种处理方法。学习了如何确定一个对象的数据类型,以及如何将它转换为其他类型。还使用简单的公式创建了新变量并重编码了现有变量。我们展示了如何对数据进行排序和对变量进行重命名,学习了如何对数据和其他数据集进行横向合并(添加变量)和纵向合并(添加观测)。
最后,我们讨论了如何保留或丢弃变量,以及如何基于一系列的准则选取观测。
在下一篇中,我们将着眼于R中不计其数的、用于创建和转换变量的算术函数、字符处理函数和统计函数。在探索了控制程序流程的方式之后,我们将了解到如何编写自己的函数。我们也将探索如何使用这些函数来整合及概括数据。
那么我们下一篇再见!
网友评论