R语言:从数据思维到数据实战
上QQ阅读APP看书,第一时间看更新

2.1.5 列表

下面接着介绍一个像机器猫的口袋一样神奇的数据结构——列表(见图2-8)。

列表可以容纳各种类型的数据对象,向量、矩阵、数据框,甚至一个列表也可以成为另一个列表的元素。下面的对象example就是一个列表,它的第一个元素是一个字符,第二个元素是一个数值向量,第三个元素是一个矩阵,第四个元素则是一个数据框。

picture

图2-8 神奇的列表
picture

列表同样是一种非常重要的数据结构,很多复杂的统计函数最终的返回结果就是列表形式,方便后续分析时按需索引。下面介绍处理列表数据的常用操作。

1.创建

创建一个新列表很容易,采用函数list(a, b, c, d)就可以把a,b,c,d四个对象组合成一个list对象。请读者尝试生成上面的示例列表example,顺便复习前面所讲的各种类型变量的创建方法。

2.基本操作

面对一个list对象,首先要学会的三种基本操作是:查看、引用和添加元素。查看时仍使用函数str( ),尤其是在列表这种数据结构中,快速查看列表内容有时在帮我们理清头绪方面大有用处。先来玩个小游戏,你能否在10秒内观察说出下面这个list的每个元素分别是什么?

picture

可能你已经看晕了,这时采用str( )函数就可以帮我们理清楚。别看这个函数非常简单,但它在实际处理列表数据时大有用处。它用层级告诉我们,这个list对象由两个子list构成,其中第一个list包含两个整数,第二个list包含两个对象:一个是英文字母的文本向量,一个是一个小list。这样就比之前清楚多了。

picture

关于引用,可以采用list对象中子元素的名字引用,也可以使用它们的序号来引用,添加list元素的操作也类似。下面的示范展示了如何用名字、序号来引用complex的第一个元素,以及如何通过这两种方式为其添加新元素。

picture
picture
picture

3.列表中的∗∗ply函数

前面介绍过一个非常有用的可以对数据进行“高效分组,同步计算”的函数:ddply( )。这个函数的优点在于把一整块数据按照某种规则分拆成多个部分,然后同步计算,各个击破。对比这里介绍的数据结构,它已经天然地把数据分好块,存储在一个列表中。我们不禁要问,有没有一种函数能够对列表中的每个元素同步计算,继续执行类似ddply( )的第二步呢?当然有,常用的lapply( ),sapply( )和mapply( ),以及tapply( ),vapply( ),rapply( )等,都可以实现这类操作,而且各具特色,感兴趣的读者可以查看相应的帮助文档。

下面以一份模拟的“老王耗子药的销售数据”为例进行说明,这三个函数到底能帮我们做什么。

近几年老王卖耗子药的价格如下:

picture

老王基本上每年每个季度都要调整一次价格,那怎么看这三年耗子药价格的水平呢?一一求均值?其实lapply( )就可以同时求出所有的均值。

picture
picture

lapply( )函数可以对列表中的每个元素实施某种“相同的操作”,在上面的示例中这个“相同的操作”就是求均值,当然也可以换成求方差、求分位数等其他可以对数值向量操作的函数,如下所示:

picture

均值求出来了,但它仍以列表形式输出,那么如何以向量、矩阵形式输出呢?此处就可以使用函数sapply( )。 sapply( )与lapply( )的工作原理类似,只是输出的结果就是想要的矩阵或向量,无须再做转换,操作结果如下所示:

picture

最后要介绍的函数是mapply( ),它能对多个list中相同位置的元素共同作用,也就是sapply( )的多变量版本。以老王耗子药的数据为例,假如现在老王已经大概了解了这几年耗子药价格的波动,但是还不够,老王想知道自己每年最终收入是多少,这就需要结合耗子药的销量数据。老王找出了他每年年底统计的各个季度的销量数据,即下面的amount:

picture

接下来需要做的是:把每年每个季度的价格与它对应的销量相乘,算出每个季度的总收入。这似乎需要在两个数据对象(列表)中操作,lapply( )和sapply( )都不符合要求。此时,就需要用到mapply( )函数,如下所示:

picture

这里,mapply( )函数分别把price的第一个元素year2014与amount的第一个元素year2014相乘,price的第二个元素year2015与amount的第二个元素year2015相乘,依次类推。由于这里所指的每个元素都是一个向量,因此它们相乘的结果仍然是一个向量,最终组合起来即是一个矩阵。需要注意的是:使用mapply( )函数需要在第一个参数中规定一个函数(这里是“∗”),后面几个参数填入列表、向量等,mapply( )的作用原理就是对后面几个参数对应位置的元素作用相应函数。

本节介绍了向量、矩阵、数据框及列表这四种常用的结构。后面还会学习各种各样的数据分析算法的R语言实现过程,亲眼见证一个有力的工具如何帮我们实现精妙的点子,如何一点点挖掘数据,让规律现身,让事实说话。当然,这一切实现的基础就是我们对数据的类型、结构的精准把握。


注释

[1]函数class( )可以显示一个数据对象的数据类型。

[2]Grouping Functions(Tapply,by,Aggregate) and the Apply Family.http://stackoverflow.com/questions/3505701/r-grouping-functions-sapply-vs-lapply-vs-apply-vs-tapply-vs-by-vs-aggregate.