R: 矩阵运算及常用函数 V - plyr Part I

来源:互联网 发布:windows热键设置 编辑:程序博客网 时间:2024/05/17 01:27
plyr是莱斯大学的Hardley Wickham大神的杰作之一(如果你没听说过这个人——ggplot也是他开发的。。。),他以split - apply - combine (SAC)的模式和理念自己写了这么一个函数包。
plyr函数系列的命名方式很简单,后缀-ply是通用名,前缀分两个部分,第一个字母是input的数据结构,第二个字母是output的数据结构。一共有六种input和output:
a: array
l: list
d: data.frame
m: multiple inputs
r: repeat multiple times
_: nothing

考虑到"_"无法做input,"m"和"r"无法做output,plyr包实际上一共提供了20个直观的函数,可以实现几乎所有用到SAC概念的数据处理模式。


回想一下这个前两篇写到的*apply一族的函数,a,l,d开头的三行plyr函数大概可以对应apply, lapply和sapply一类;而m,r开头的两行大概对应的是mapply和replicate函数。

-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-

1. a*ply: 输入项为array的函数
函数主要的参数有: .data, .margins 以及 .fun。作用跟apply里的X, MARGIN和FUN一样。

先看看自带的例子,这里用到了plyr包里的ozone数据
> str(ozone)
 num [1:24, 1:24, 1:72] 260 258 258 254 252 252 250 248 248 248 ...
- attr(*, "dimnames")=List of 3
  ..$ lat : chr [1:24] "-21.2" "-18.7" "-16.2" "-13.7" ...
  ..$ long: chr [1:24] "-113.8" "-111.3" "-108.8" "-106.3" ...
  ..$ time: chr [1:72] "1" "2" "3" "4" ...

这是一个24 x 24 x 72的三维数组,三个维度分别是维度、经度和时间。记录了1995到2000年之间每个月的臭氧平均值。

> head(aaply(ozone, 2, mean))
  -113.8   -111.3   -108.8   -106.3   -103.8   -101.3
268.5637 268.5509 267.9213 267.1319 267.1748 266.9769
> head(alply(ozone, 2, mean))
$`1`
[1] 268.5637

$`2`
[1] 268.5509

$`3`
[1] 267.9213

$`4`
[1] 267.1319

$`5`
[1] 267.1748

$`6`
[1] 266.9769

> head(adply(ozone, 2, mean))
    long       V1
1 -113.8 268.5637
2 -111.3 268.5509
3 -108.8 267.9213
4 -106.3 267.1319
5 -103.8 267.1748
6 -101.3 266.9769
 
上面的3个例子中,a*ply返回的是以经度为基准(第二维度),不同维度和时间点上的臭氧平均值。
这里aaply将结果压缩成一维数组,也就是一个vector(可以用is.vector来检查),vector的names即24个不同的经度点。alply返回一个list,adply返回一个data frame。

plyr包还提供了一系列小函数,有很多可以拿出来使用,如each(),用于合并多个函数供*ply返回,对数据处理的方便性不言而喻。
(用> library(help = plyr)可以查看这个包里附带的所有函数。)
> head(aaply(ozone, 2, each(mean, min, max)))
       
long         mean min max
  -113.8 268.5637 232 390
  -111.3 268.5509 232 368
  -108.8 267.9213 232 368
  -106.3 267.1319 234 362
  -103.8 267.1748 234 354
  -101.3 266.9769 232 354

这些函数也可以与其他plyr包外的函数结合使用:
> apply(ozone, 2, each(mean, min, max))[,1:6]
      long
         -113.8   -111.3   -108.8   -106.3   -103.8   -101.3
  mean 268.5637 268.5509 267.9213 267.1319 267.1748 266.9769
  min  232.0000 232.0000 232.0000 234.0000 234.0000 232.0000
  max  390.0000 368.0000 368.0000 362.0000 354.0000 354.0000

*ply一系中还有一些其它参数,如.progress,用于创建进度条,当数据量大的时候可以通过进度条来查看*ply的处理进度。当数据少的时候,可以不考虑使用它,因为这个时候.progress反而会拖慢计算进度。
> l_ply(1:100000, identity, .progress = progress_text(char = "."))
  |...................................................................| 100%

自己在做数据处理的时候可根据不同需求调用相应的参数,一般来说只需按各参数默认值运行。

-+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+-

说到这里,我们需要理解一下*ply系列函数的在分解不同维度input时的逻辑(在这个系列的第一篇里有提到过Hardley大神写过的一篇文章,The Split-Apply-Combine Strategy for Data Analysis,下面的解释是直接从这篇文章里提取出来的)。



对于2维数组,我们有三种方法分解,.margins = 1,按行分解;.margins = 2,按列分解;.margins = c(1,2),对每个单元格逐个运算。



当input扩大到三维时,我们有七种方法去分解。可以按面分解,此时只需要明确是哪一面即可,如.margins = 1;可以按线分解,即按三个维度上任意两个维度的交界线分解,如.margins = c(1,2);也可以逐个单元进行分解,即以三个维度的交界点来进行分解,.margins = 1:3。

扩展到更多维度,也按照此种方法类推。


0 0
原创粉丝点击