EXCEL中的很强大的功能就是数据透视表,不得不说,透视表解决了很多数据汇总的问题,包括可以计数、求和、均值等一系列操作;然而数据透视表比较慢,而且对于后续的处理不是很友好。既然用R来分析数据,则不能把所有数据放在excel里然后用R分析,通过R in action的启发,加上很多自己的实验,总结三种透视表的方法。
【一】SQL语言的透视表
一般在数据分析处理前,从数据库中提取会有若干字段的csv,我们可以利用R进行二次加工,看一个例子:
首先建立一个data.frame-test
Region Surname Age height salary
1 辽宁 王 25 180 100
2 北京 杨 27 185 50
3 山东 王 27 185 80
4 辽宁 齐 27 190 55
我们首先要统计一下,各省市的平均年龄是多少?这个时候的逻辑其实是按照区域汇总,然后求均值
首先用sql包
library(sqldf)
然后用SQL语言进行选择求值,需要注意的是,SQL中的均值和R不同,R中是mean函数,SQL是avg。
用如下语句,其实就是选择Region这一列,对Age求平均值,最后以Region分组
sqldf('select Region, avg(Age) from test group by Region')
结果如下:
Region avg(Age)
1 北京 27
2 山东 27
3 辽宁 26
同理,如果我要统计各姓氏的工资总和,
sqldf('select Region, avg(Age) from test group by Region')
Surname sum(salary)
1 杨 50
2 王 180
3 齐 55
顺便我要按照工资高低排序
sqldf('select Surname, sum(salary) from test group by surname order by salary desc')
order by 是排序,desc是排倒序,结果为
Surname sum(salary)
1 王 180
2 齐 55
3 杨 50
其实这就是初步的实现了数据透视表的功能,但是这个格式还是字段型的格式,也就是一行是一个字段的列表,如果想分类汇总,可能在excel中还需要sumif,sumifs,sumproduct等函数做出美观的效果。如果想直接按照行列式的数据透视表,就需要下面的方法。
【二】reshape包的透视表
reshape包的透视表可以做出和excel一模一样的功能,但是首先需要数据标准化,也就是melt,这部分的数据标准化其实就是标准化成字段模式,举个例子:
这个表f
王 齐 杨
salary 180 55 50
标准化之后就成了之前的表e:
Surname sum(salary)
1 王 180
2 齐 55
3 杨 50
具体的过程可以用如下代码
library(reshape2)
melt(f,varnames = c('field','Surname'))
第一个是调用reshape2包,因为reshape包竟然无法使用varnames和value.names函数,也不知道为什么;然后处理一下数据集,让他看起来和表e一样
field Surname value
1 salary 王 180
2 salary 齐 55
3 salary 杨 50
下面说说区别,看到表e有三列,而之前的表e的第一列可以认为是列序号,这就是一个微小的差异,也就是针对melt后的表,一定要有一个字段的,而字段不在表头,在行上,基于这个推论,也就是说
melt后的标准化数据一定至少有三列
即使一列是没什么用的。
melt后就可以开始cast了,这里面不用这个例子,用最原始的表test
之前说过,test已经是标准化之后的数据了,我们现在想取region和surname下的salary水平,利用如下代码
library(reshape)
cast(test,Region~Surname,value='salary')
结果如下:
Region 齐 王 杨
1 北京 NA NA 50
2 辽宁 55 100 NA
3 山东 NA 80 NA
或者看身高的均值g
cast(test,Region~Age,value='height',mean,na.rm=T)
Region 25 27
1 北京 NaN 185
2 辽宁 180 190
3 山东 NaN 185
可以看到有很多NA和NAN的值,因为我们的原始数据不是在每个交叉表里都有,所以会有NAN值
可以利用
na.omit(g)
删除含有缺失值的一行
剩下:
Region 25 27
2 辽宁 180 190
或者为了分析方便,如后续的分析应用到mean,sum等加上na.rm=T
再或者为了表示NA值就是0,可以赋值
g[is.na(g)]<-0
Region 25 27
1 北京 0 185
2 辽宁 180 190
3 山东 0 185
除此之外,还有subset函数以及其他的针对数据异常数据的提取和改名,可以保证随心所欲的处理R的数据源。
【三】aggregate函数
还是原来的test数据框
Region Surname Age height salary
1 辽宁 王 25 180 100
2 北京 杨 27 185 50
3 山东 王 27 185 80
4 辽宁 齐 27 190 55
这时候,如果我想要对姓氏的年龄做平均,利用
h<-aggregate(test$Age*,by=list(test$Surname),mean)
得到
h
Group.1 x
1 齐 27
2 王 26
3 杨 27
或者直接改掉Group.1的名字
h<-aggregate(test$Age,by=list(Surname=Surname),mean)
得到
h
Surname x
1 齐 27
2 王 26
3 杨 27
同理,我要是想要算区域的总工资
j<-aggregate(test$salary,by=list(Region=Region),sum)
则
j
Region x
1 北京 50
2 辽宁 155
3 山东 80
同时,aggregate函数还可以对多列进行汇总,比如对身高和工资的汇总
j<-aggregate(test$salary,by=list(Age=Age,height=height),sum)
这里是对test里的salary一列汇总,同时条件是筛选出age和height相同的进行加总,结果为
j
Age height x
1 25 180 100
2 27 185 130
3 27 190 55
THE END