一、通过重新构建数据进行整形

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

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

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

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

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

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

二、transform 和 within函数

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

  1. > head(airquality,2)
  2. Ozone Solar.R Wind Temp Month Day
  3. 1    41     190  7.4   67     5   1
  4. 2    36     118  8.0   72     5   2
  5. > aq <- transform(airquality, loglog.ozone=log(Ozone))
  6. > head(airquality,2)
  7. Ozone Solar.R Wind Temp Month Day
  8. 1    41     190  7.4   67     5   1
  9. 2    36     118  8.0   72     5   2
  10. > head(aq,2)
  11. Ozone Solar.R Wind Temp Month Day log.ozone
  12. 1    41     190  7.4   67     5   1  3.713572
  13. 2    36     118  8.0   72     5   2  3.583519

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

  1. > aq <- transform(airquality, loglog.ozone=log(Ozone), Ozone=NULL, WindWind=Wind^2)
  2. > head(aq,2)
  3. Solar.R  Wind Temp Month Day log.ozone
  4. 1     190 54.76   67     5   1  3.713572
  5. 2     118 64.00   72     5   2  3.583519
  6. > aq <- transform(airquality, loglog.ozone=log(Ozone), Ozone=NULL, Month=NULL, WindWind=Wind^2)
  7. > head(aq,2)
  8. Solar.R  Wind Temp Day log.ozone
  9. 1     190 54.76   67   1  3.713572
  10. 2     118 64.00   72   2  3.583519

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

  1. > aq <- within(airquality, {
  2. + log.ozone <- log(Ozone)
  3. + squared.wind <- Wind^2
  4. + rm(Ozone, Wind)
  5. + } )
  6. > head(aq,2)
  7. Solar.R Temp Month Day squared.wind log.ozone
  8. 1     190   67     5   1        54.76  3.713572
  9. 2     118   72     5   2        64.00  3.583519
  10. > (x <- list(a=1:3, b=letters[3:10], c=LETTERS[9:14]))
  11. $a
  12. [1] 1 2 3
  13. $b
  14. [1] "c" "d" "e" "f" "g" "h" "i" "j"
  15. $c
  16. [1] "I" "J" "K" "L" "M" "N"
  17. > within(x, {log.a <- log(a); d <- paste(b, c, sep=':'); rm(b)})
  18. $a
  19. [1] 1 2 3
  20. $c
  21. [1] "I" "J" "K" "L" "M" "N"
  22. $d
  23. [1] "c:I" "d:J" "e:K" "f:L" "g:M" "h:N" "i:I" "j:J"
  24. $log.a
  25. [1] 0.0000000 0.6931472 1.0986123
  26. > within(x, {log.a <- log(a); d <- paste(b, c, sep=':'); rm(b,c)})
  27. $a
  28. [1] 1 2 3
  29. $b   #为什么删除两个列表元素会得到这样的结果?
  30. NULL
  31. $c
  32. NULL
  33. $d
  34. [1] "c:I" "d:J" "e:K" "f:L" "g:M" "h:N" "i:I" "j:J"
  35. $log.a
  36. [1] 0.0000000 0.6931472 1.0986123

三、reshape、stack和unstack 函数

reshape是R base/stats的函数,主要用于数据框长格式和宽格式之间的转换。reshape函数的参数很多,不容易记,牛人Hadley Wickham搞出reshape和reshape2包以后这个函数几乎被人遗忘:

  1. reshape(data, varying = NULL, v.names = NULL, timevar = "time",
  2. idvar = "id", ids = 1:NROW(data),
  3. times = seq_along(varying[[1]]),
  4. drop = NULL, direction, new.row.names = NULL,
  5. sep = ".",
  6. split = if (sep == "") {
  7. list(regexp = "[A-Za-z][0-9]", include = TRUE)
  8. } else {
  9. list(regexp = sep, include = FALSE, fixed = TRUE)}
  10. )

既然可以被遗忘,那就等你走投无路的时候(估计不会有这样的情况发生)再去了解它吧。

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

  1. > 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))
  2. > x
  3. CK  T1  T2
  4. 1 1.1 2.1 2.5
  5. 2 1.2 2.2 2.2
  6. 3 1.1 2.3 2.3
  7. 4 1.5 2.1 2.1

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

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

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

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

四、reshape/reshape2 包

Hadley Wickham,牛人,很牛X的一个人,写了很多R语言包,著名的有ggplot2, plyr, reshape/reshape2等。reshape2包是reshape包的重写版,用reshape2就行,都在CRAN源中,用install.packages函数就可以安装。reshape/reshape2的函数很少,一般用户直接使用的是melt, acast 和 dcast 函数。

melt是溶解/分解的意思,即拆分数据。reshape/reshape2的melt函数是个S3通用函数,它会根据数据类型(数据框,数组或列表)选择melt.data.frame, melt.array 或 melt.list函数进行实际操作。

如果是数组(array)类型,melt的用法就很简单,它依次对各维度的名称进行组合将数据进行线性/向量化。如果数组有n维,那么得到的结果共有n+1列,前n列记录数组的位置信息,最后一列才是观测值:

  1. > datax <- array(1:8, dim=c(2,2,2))
  2. > melt(datax)
  3. Var1 Var2 Var3 value
  4. 1    1    1    1     1
  5. 2    2    1    1     2
  6. 3    1    2    1     3
  7. 4    2    2    1     4
  8. 5    1    1    2     5
  9. 6    2    1    2     6
  10. 7    1    2    2     7
  11. 8    2    2    2     8
  12. > melt(datax, varnames=LETTERS[24:26],value.name="Val")
  13. X Y Z Val
  14. 1 1 1 1   1
  15. 2 2 1 1   2
  16. 3 1 2 1   3
  17. 4 2 2 1   4
  18. 5 1 1 2   5
  19. 6 2 1 2   6
  20. 7 1 2 2   7
  21. 8 2 2 2   8

如果是列表数据,melt 函数将列表中的数据拉成两列,一列记录列表元素的值,另一列记录列表元素的名称;如果列表中的元素是列表,则增加列变量存储元素名称。元素值排列在前,名称在后,越是顶级的列表元素名称越靠后:

  1. > datax <- list(agi="AT1G10000", GO=c("GO:1010","GO:2020"), KEGG=c("0100", "0200", "0300"))
  2. > melt(datax)
  3. value   L1
  4. 1 AT1G10000  agi
  5. 2   GO:1010   GO
  6. 3   GO:2020   GO
  7. 4      0100 KEGG
  8. 5      0200 KEGG
  9. 6      0300 KEGG
  10. > melt(list(at_0100=datax))
  11. value   L2      L1
  12. 1 AT1G10000  agi at_0100
  13. 2   GO:1010   GO at_0100
  14. 3   GO:2020   GO at_0100
  15. 4      0100 KEGG at_0100
  16. 5      0200 KEGG at_0100
  17. 6      0300 KEGG at_0100

如果数据是数据框类型,melt的参数就稍微复杂些:

  1. melt(data, id.vars, measure.vars,
  2. variable.name = "variable", ..., na.rm = FALSE,
  3. value.name = "value")

其中 id.vars 是被当做维度的列变量,每个变量在结果中占一列;measure.vars 是被当成观测值的列变量,它们的列变量名称和值分别组成 variable 和 value两列,列变量名称用variable.name 和 value.name来指定。我们用airquality数据来看看:

  1. > str(airquality)
  2. 'data.frame':   153 obs. of  6 variables:
  3. $ Ozone  : int  41 36 12 18 NA 28 23 19 8 NA ...
  4. $ Solar.R: int  190 118 149 313 NA NA 299 99 19 194 ...
  5. $ Wind   : num  7.4 8 12.6 11.5 14.3 14.9 8.6 13.8 20.1 8.6 ...
  6. $ Temp   : int  67 72 74 62 56 66 65 59 61 69 ...
  7. $ Month  : int  5 5 5 5 5 5 5 5 5 5 ...
  8. $ Day    : int  1 2 3 4 5 6 7 8 9 10 ...

如果打算按月份分析臭氧和太阳辐射、风速、温度三者(列2:4)的关系,我们把它转成长格式数据框:

  1. > aq <- melt(airquality, var.ids=c("Ozone", "Month", "Day"),
  2. + measure.vars=c(2:4), variable.name="V.type", value.name="value")
  3. > str(aq)
  4. 'data.frame':   459 obs. of  5 variables:
  5. $ Ozone : int  41 36 12 18 NA 28 23 19 8 NA ...
  6. $ Month : int  5 5 5 5 5 5 5 5 5 5 ...
  7. $ Day   : int  1 2 3 4 5 6 7 8 9 10 ...
  8. $ V.type: Factor w/ 3 levels "Solar.R","Wind",..: 1 1 1 1 1 1 1 1 1 1 ...
  9. $ value : num  190 118 149 313 NA NA 299 99 19 194 ...

var.ids 可以写成id,measure.vars可以写成measure。id(即var.ids)和 观测值(即measure.vars)这两个参数可以只指定其中一个,剩余的列被当成另外一个参数的值;如果两个都省略,数值型的列被看成观测值,其他的被当成id。如果想省略参数或者去掉部分数据,参数名最好用 id/measure,否则得到的结果很可能不是你要的:

  1. > str(melt(airquality, var.ids=c(1,5,6), measure.vars=c(2:4)))
  2. 'data.frame':   459 obs. of  5 variables:
  3. $ Ozone   : int  41 36 12 18 NA 28 23 19 8 NA ...
  4. $ Month   : int  5 5 5 5 5 5 5 5 5 5 ...
  5. $ Day     : int  1 2 3 4 5 6 7 8 9 10 ...
  6. $ variable: Factor w/ 3 levels "Solar.R","Wind",..: 1 1 1 1 1 1 1 1 1 1 ...
  7. $ value   : num  190 118 149 313 NA NA 299 99 19 194 ...
  8. > str(melt(airquality, var.ids=1, measure.vars=c(2:4)))   #看这里,虽然id只引用了一列,但结果却不是这样
  9. 'data.frame':   459 obs. of  5 variables:
  10. $ Ozone   : int  41 36 12 18 NA 28 23 19 8 NA ...
  11. $ Month   : int  5 5 5 5 5 5 5 5 5 5 ...
  12. $ Day     : int  1 2 3 4 5 6 7 8 9 10 ...
  13. $ variable: Factor w/ 3 levels "Solar.R","Wind",..: 1 1 1 1 1 1 1 1 1 1 ...
  14. $ value   : num  190 118 149 313 NA NA 299 99 19 194 ...
  15. > str(melt(airquality, var.ids=1))  #这样用更惨,结果不是我们要的吧?
  16. Using  as id variables
  17. 'data.frame':   918 obs. of  2 variables:
  18. $ variable: Factor w/ 6 levels "Ozone","Solar.R",..: 1 1 1 1 1 1 1 1 1 1 ...
  19. $ value   : num  41 36 12 18 NA 28 23 19 8 NA ...
  20. > str(melt(airquality, id=1))  #这样才行
  21. 'data.frame':   765 obs. of  3 variables:
  22. $ Ozone   : int  41 36 12 18 NA 28 23 19 8 NA ...
  23. $ variable: Factor w/ 5 levels "Solar.R","Wind",..: 1 1 1 1 1 1 1 1 1 1 ...
  24. $ value   : num  190 118 149 313 NA NA 299 99 19 194 ...

数据整容有什么用?当然有。别忘了reshape2和ggplot2都是Hadley Wickham的作品,melt 以后的数据(称为molten数据)用ggplot2做统计图就很方便了,可以快速做出我们需要的图形:

  1. library(ggplot2)
  2. aq$Month <- factor(aq$Month)
  3. p <- ggplot(data=aq, aes(x=Ozone, y=value, color=Month)) + theme_bw()
  4. p + geom_point(shape=20, size=4) + geom_smooth(aes(group=1), fill="gray80") + facet_wrap(~V.type, scales="free_y")

melt获得的数据(molten data)可以用 acast 或 dcast 还原。acast获得数组,dcast获得数据框。和unstack函数一样,cast函数使用公式参数。公式的左边每个变量都会作为结果中的一列,而右边的变量被当成因子类型,每个水平都会在结果中产生一列。

  1. > head(dcast(aq, Ozone+Month+Day~V.type))
  2. Ozone Month Day Solar.R Wind Temp
  3. 1     1     5  21       8  9.7   59
  4. 2     4     5  23      25  9.7   61
  5. 3     6     5  18      78 18.4   57
  6. 4     7     5  11      NA  6.9   74
  7. 5     7     7  15      48 14.3   80
  8. 6     7     9  24      49 10.3   69

cast函数的作用不只是还原数据,还可以使用函数对数据进行汇总(aggregate)。事实上,melt函数是为cast服务的,目的是使用cast函数对数据进行aggregate:

  1. > dcast(aq, Month~V.type, fun.aggregate=mean, na.rm=TRUE)
  2. Month  Solar.R      Wind     Temp
  3. 1     5 181.2963 11.622581 65.54839
  4. 2     6 190.1667 10.266667 79.10000
  5. 3     7 216.4839  8.941935 83.90323
  6. 4     8 171.8571  8.793548 83.96774
  7. 5     9 167.4333 10.180000 76.90000

五、plyr 包

plyr 的功能已经远远超出数据整容的范围,Hadley在plyr中应用了split-apply-combine的数据处理哲学,即:先将数据分离,然后应用某些处理函数,最后将结果重新组合成所需的形式返回。某些人士喜欢用“揉”来表述这样的数据处理;“揉”,把数据当面团捣来捣去,很哲,砖家们的砖头落下来,拍死人绝不偿命

先别哲了,来点实际的:plyr的函数命名方式比较规律,很容易记忆和使用。比如 a开头的函数aaply, adply 和 alply 将数组(array)分别转成数组、数据框和列表;daply, ddply 和 dlply 将数据框分别转成数组、数据框和列表;而laply, ldaply, llply将列表(list)分别转成数组、数据框和列表。

下面我们看看如何使用ldply函数将ath1121501.db包中的KEGG列表数据转成数据框:

  1. > library(ath1121501.db)
  2. > keggs <- as.list(ath1121501PATH[mappedkeys(ath1121501PATH)])
  3. > head(ldply(keggs, paste, collapse='; '))
  4. .id                                              V1
  5. 1 261579_at                                           00190
  6. 2 261569_at                                           04712
  7. 3 261583_at 00010; 00020; 00290; 00620; 00650; 01100; 01110
  8. 4 261574_at                      00903; 00945; 01100; 01110
  9. 5 261043_at                             00051; 00520; 01100
  10. 6 261044_at                                           04122

plyr包的函数较多,不再一一介绍,更多用法请参考它的在线帮助,Hadley 也写了很详细的tutorial:http://plyr.had.co.nz/09-user/

原文链接:http://helloxxxxxx.blog.163.com/blog/static/21601509520133343821837/?latestBlog

R语言进阶之4:数据整形(reshape)的更多相关文章

  1. 【R笔记】R语言进阶之4:数据整形(reshape)

    R语言进阶之4:数据整形(reshape) 2013-05-31 10:15 xxx 网易博客 字号:T | T 从不同途径得到的数据的组织方式是多种多样的,很多数据都要经过整理才能进行有效的分析,数 ...

  2. R语言中的横向数据合并merge及纵向数据合并rbind的使用

    R语言中的横向数据合并merge及纵向数据合并rbind的使用 我们经常会遇到两个数据框拥有相同的时间或观测值,但这些列却不尽相同.处理的办法就是使用merge(x, y ,by.x = ,by.y ...

  3. R语言系列:生成数据

    R语言系列:生成数据 (2014-05-04 17:41:57) 转载▼ 标签: r语言 教育 分类: 生物信息 生成规则数据1.使用“:“,如x=1:10,注意该方法既可以递增也可以递减,如y=10 ...

  4. R语言︱噪声数据处理、数据分组——分箱法(离散化、等级化)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 分箱法在实际案例操作过程中较为常见,能够将一些 ...

  5. R语言数据集合并、数据增减、不等长合并

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 数据选取与简单操作: which 返回一个向量 ...

  6. 用R语言实现对不平衡数据的四种处理方法

    https://www.weixin765.com/doc/gmlxlfqf.html 在对不平衡的分类数据集进行建模时,机器学**算法可能并不稳定,其预测结果甚至可能是有偏的,而预测精度此时也变得带 ...

  7. R语言读取matlab中数据

    1. 在matlab中将数据保存到*.mat 文件夹 save("data.mat","data","label")#将data和label ...

  8. R语言:导入导出数据

    主要学习如何把几种常用的数据格式导入到R中进行处理,并简单介绍如何把R中的数据保存为R数据格式和csv文件. 1.保存和加载R的数据(与R.data的交互:save()函数和load()函数) a & ...

  9. DT包 -- R语言中自定义表格数据

    DT 包提供了 JavaScript 库 DataTables 的一个R接口,它使得R对象(矩阵或数据框)可以在HTML页面上显示为表格. 该包的DataTables函数生成的表格提供了数据的筛选.分 ...

随机推荐

  1. 工作总结 MVC 验证 [Required] 必填 与 string 小知识

    例如 添加页面有个 title  字段  设置了 [Required] 不填的时候   设置 还是验证不通过 设置为 还是不通过  说明了  验证只与页面上传不传值有关   与在后台设不设置值 无关. ...

  2. 什么是Asterisk,它如何帮助我们的呼叫中心?

    如今的呼叫中心与过去的呼叫中心有很大差异.过去,一间房屋或一座大楼,装上硬接线的POTS电话,招聘几名员工就可以建立一个呼叫中心.如今,这样的情形已经一去不复返,因为有许多新技术让呼叫中心变得更像是一 ...

  3. ASM_Oracle ASM的常用命令(汇总)

    2014-07-02 Created By BaoXinjian

  4. linux write系统调用如何实现

    在Linux下我们在使用设备的时候,都会用到write这个函数,通过这个函数我们可以象使用文件那样向设备传送数据.可是为什么用户使用write函数就可以把数据写到设备里面去,这个过程到底是怎么实现的呢 ...

  5. mvn test 执行testng测试用例

    maven项目,把testng用例防止test目录下,配置pom.xml 文件如下,执行mvn test 能自动执行testng里面的用例 <project xmlns="http:/ ...

  6. 如何用 LaTeX 撰写博士学位论文?

    如何用 LaTeX 撰写博士学位论文? 序 一直觉得有必要写这样一篇文章,因为学位论文从格式上说更像一本书,与文章 的排版不同,不仅多出目录等文章没有的部分,而且一般要设置页眉页脚方便阅 读查找.学校 ...

  7. IIS 的几个小技巧

    1.向 IIS 中安装 .NET 应用程序池 如果先安装了 IIS,后安装了 .NET,就需要向 IIS 中注册 ASP.NET . (有的版本 .NET 安装后可能不会在 IIS 中体现,比如貌似 ...

  8. perl的内置函数scalar

    scalar可以求数组的长度,但是,在scalar的说明里面并没有这一项. Forces EXPR to be interpreted in scalar context and returns th ...

  9. ISE联合modelsim功能仿真和综合后仿真

    1.代码输入 (1).新建一个ISE工程,名字为count4. (2).新建一个verilog文件 (3).选择verilog module 输入file name为count4,单击next默认知道 ...

  10. 2014年百度之星资格赛第四题Labyrinth

    Problem Description 度度熊是一仅仅喜欢探险的熊.一次偶然落进了一个m*n矩阵的迷宫.该迷宫仅仅能从矩阵左上角第一个方格開始走.仅仅有走到右上角的第一个格子才算走出迷宫,每一次仅仅能 ...