R语言中数据整形

前言

  从不同途径得到的数据的组织方式是多种多样的,很多数据都要经过整理才能进行有效的分析,数据整形不仅仅是为了改善数据的外观,也是进行一些统计分析和作图前必要的步骤。数据整形和数据凝练/汇总往往密不可分,这是门学问,是R语言数据处理的内容之一。

目录

 1. 通过重新构建数据进行整形

 2. transform 和 within 函数

 3. stack 和 unstack 函数

1. 通过重新构建数据进行整形

  数据整形最直接的思路就把数据全部向量化,然后按要求用向量构建其他类型的数据。这样是不是会产生大量的中间变量、占用大量内存?没错。R语言的任何函数(包括赋值)操作都会有同样的问题,因为R函数的参数传递方式是传值不传址,变量不可能原地址修改后再放回原地址。

  矩阵和多维数组的向量化有直接的类型转换函数: as.vector,向量化后的结果顺序是先列后行再其他:

> (x <- matrix(1:4, ncol=2))  #为节省空间,下面的结果省略了一些空行 
         [,1] [,2] 
    [1,]    1    3 
    [2,]    2    4 
    > as.vector(x) 
    [1] 1 2 3 4 
    > (x <- array(1:8, dim=c(2,2,2))) 
    , , 1 
         [,1] [,2] 
    [1,]    1    3 
    [2,]    2    4 
    , , 2 
         [,1] [,2] 
    [1,]    5    7 
    [2,]    6    8 
    > as.vector(x) 
    [1] 1 2 3 4 5 6 7 8

  列表向量化可以用unlist,数据框本质是元素长度相同的列表,所以也用unlist:

> (x <- list(x=1:3, y=5:10)) 
    $x 
    [1] 1 2 3 
    $y 
     
    [1]  5  6  7  8  9 10 
    > unlist(x) 
    x1 x2 x3 y1 y2 y3 y4 y5 y6  
     1  2  3  5  6  7  8  9 10  
    > x <- data.frame(x=1:3, y=5:7) 
    > unlist(x) 
    x1 x2 x3 y1 y2 y3  
     1  2  3  5  6  7

  其他类型的数据一般都可以通过数组、矩阵或列表转成向量。一些软件包有自定义的数据类型,如果考虑周到的话应该会有合适的类型转换函数。

2. transform 和 within 函数

  transform 函数对数据框进行操作,作用是为原数据框增加新的列变量。但应该注意的是“原数据框”根本不是原来的那个数据框,而是一个它的拷贝。下面代码为airquality数据框增加了一列log.ozone,但因为没有把结果赋值给原变量名,所以原数据是不变的:

> head(airquality,2) 
      Ozone Solar.R Wind Temp Month Day 
    1    41     190  7.4   67     5   1 
    2    36     118  8.0   72     5   2 
    > aq <- transform(airquality, log.ozone=log(Ozone)) 
    > head(airquality,2) 
      Ozone Solar.R Wind Temp Month Day 
    1    41     190  7.4   67     5   1 
    2    36     118  8.0   72     5   2 
    > head(aq,2) 
      Ozone Solar.R Wind Temp Month Day log.ozone 
    1    41     190  7.4   67     5   1  3.713572 
    2    36     118  8.0   72     5   2  3.583519

  transform可以增加新列变量,可以改变列变量的值,也可以通过NULL赋值的方式删除列变量:

> aq <- transform(airquality, log.ozone=log(Ozone), Ozone=NULL, Wind=Wind^2) 
    > head(aq,2) 
      Solar.R  Wind Temp Month Day log.ozone 
    1     190 54.76   67     5   1  3.713572 
    2     118 64.00   72     5   2  3.583519 
     
    > aq <- transform(airquality, log.ozone=log(Ozone), Ozone=NULL, Month=NULL, Wind=Wind^2) 
    > head(aq,2) 
      Solar.R  Wind Temp Day log.ozone 
    1     190 54.76   67   1  3.713572 
    2     118 64.00   72   2  3.583519

  within 比 transform 灵活些,除数据框外还可以使用其他类型数据,但用法不大一样,而且函数似乎也不够完善:

> aq <- within(airquality, { 
    + log.ozone <- log(Ozone) 
    + squared.wind <- Wind^2 
    + rm(Ozone, Wind) 
    + } ) 
    > head(aq,2) 
      Solar.R Temp Month Day squared.wind log.ozone 
    1     190   67     5   1        54.76  3.713572 
    2     118   72     5   2        64.00  3.583519 
     
    > (x <- list(a=1:3, b=letters[3:10], c=LETTERS[9:14])) 
    $a 
    [1] 1 2 3 
    $b 
    [1] "c" "d" "e" "f" "g" "h" "i" "j" 
    $c 
    [1] "I" "J" "K" "L" "M" "N" 
     
    > within(x, {log.a <- log(a); d <- paste(b, c, sep=':'); rm(b)}) 
    $a 
    [1] 1 2 3 
    $c 
    [1] "I" "J" "K" "L" "M" "N" 
    $d 
    [1] "c:I" "d:J" "e:K" "f:L" "g:M" "h:N" "i:I" "j:J" 
    $log.a 
    [1] 0.0000000 0.6931472 1.0986123 
    > within(x, {log.a <- log(a); d <- paste(b, c, sep=':'); rm(b,c)}) 
    $a 
    [1] 1 2 3 
    $b   #为什么删除两个列表元素会得到这样的结果? 
     
    NULL 
    $c 
    NULL 
    $d 
    [1] "c:I" "d:J" "e:K" "f:L" "g:M" "h:N" "i:I" "j:J" 
    $log.a 
    [1] 0.0000000 0.6931472 1.0986123

3. stack 和 unstack 函数

  stack 和 unstack 的作用和reshape类似,用于数据框/列表的长、宽格式之间转换。数据框宽格式是我们记录原始数据常用的格式,类似这样:

> x <- data.frame(CK=c(1.1, 1.2, 1.1, 1.5), T1=c(2.1, 2.2, 2.3, 2.1), T2=c(2.5, 2.2, 2.3, 2.1)) 
    > x 
       CK  T1  T2 
    1 1.1 2.1 2.5 
    2 1.2 2.2 2.2 
    3 1.1 2.3 2.3 
    4 1.5 2.1 2.1

  一般统计和作图用的是长格式,stack可以做这个:

> (xx <- stack(x)) 
       values ind 
    1     1.1  CK 
    2     1.2  CK 
    3     1.1  CK 
    4     1.5  CK 
    5     2.1  T1 
    6     2.2  T1 
    7     2.3  T1 
    8     2.1  T1 
    9     2.5  T2 
    10    2.2  T2 
    11    2.3  T2 
    12    2.1  T2

  而unstack的作用正好和stack相反,但是要注意它的第二个参数是公式类型:公式左边的变量是值,右边的变量会被当成因子类型,它的每个水平都会形成一列:

> unstack(xx, values~ind) 
       CK  T1  T2 
    1 1.1 2.1 2.5 
    2 1.2 2.2 2.2 
    3 1.1 2.3 2.3 
    4 1.5 2.1 2.1

参考资料