在Excel中我们可以很方便的对数据进行排序、筛选、分类汇总等基本操作,R语言中没有这种傻瓜式的一键操作,如何才能完成这种操作?
一、排序
1、单变量序列排序
单变量序列的排序常用到rank、sort和order函数。
给一个例子:
-
> a <- c(3, 1, 5)
-
> rank(a)
-
[1] 2 1 3
-
> sort(a)
-
[1] 1 3 5
-
> order(a)
-
[1] 2 1 3
下面简单解释一下:rank用来计算序列中每个元素的秩,这里的“秩”可以理解为该元素在序列中由小到大排列的次序,上面例子给出的序列[3, 1, 5]中,1最小,5最大,3居中,于是1的秩为1,3的秩为2,5的秩为3,[3, 1, 5]对应的秩的结果就是[2,1, 3];sort函数给出的是排序后的结果,比方说序列[3,1, 5]使用sort按升序规则排序后的结果是[1, 3, 5];而order函数给出的是排序后的序列中各元素在原始序列中的位置,序列[3, 1, 5]按升序规则排序后的结果是[1, 3, 5] ,其中[1, 3, 5]在原始序列中的位置是[2, 1, 3]。
接下来介绍一下这三个函数的参数:
rank(x,na.last = TRUE,
ties.method = c("average","first", "last", "random", "max","min"))
order(...,na.last = TRUE, decreasing = FALSE,
method = c("auto","shell", "radix"))
sort(x,decreasing = FALSE, na.last = NA, ...)
x或... :要进行排序的序列;
na.last:表示对缺失值的处理办法,若为TRUE则将缺失值排在最后,若为FALSE则排在最前,若为NA则排序时先将缺失值剔除;
ties.method:表示对序列有“结”(即序列中存在相同的元素)时的处理方法,可以有"average","first", "last", "random", "max","min"等选择;
decreasing : 默认为FALSE表示按升序排列,若为TRUE则按降序排列;
method:表示排序使用的算法,可以有"auto","shell", "radix"等选择。
2、数据表(矩阵)排序
如何像Excel中那样将数据表按某列升序或降序排列?我们可以使用order函数巧妙的完成这个操作,以R语言自带的鸢尾花(iris)数据集为例:
> head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa
可以看到,该数据集有Sepal.Length、Sepal.Width、Petal.Length、Petal.Width和Species五个变量,下面我们按照花萼宽度(Sepal.Width)进行升降序排列:
## 升序 iris[order(iris$Sepal.Width), ] ## 降序 iris[order(iris$Sepal.Width, decreasing= T), ]
升序:
降序:
除此之外,升降序排列还可以使用dplyr包的arrange函数。arrange函数用法简单,使用形式为arrange(数据表名,变量名),如果是降序排列则可以arrange(数据表名,-变量名)或arrange(数据表名,desc(变量名))。特别值得一提的是,arrange函数还有arrange(数据表名,变量名1,变量名2,...)这种形式的用法,表示如果数据在“变量1”的值相同时按照“变量2”排序。
library(dplyr) ## Sepal.Width升序 arrange(iris, Sepal.Width) ## Sepal.Width降序 arrange(iris, desc(Sepal.Width)) ## Sepal.Width升序,当Sepal.Width相同时按Petal.Length降序 arrange(iris, Sepal.Width,-Petal.Length)
通过对比可以看到,使用arrange进行排序后,数据表的行号重新从1开始排列了,而使用order的方式中排序后的数据表的行号仍然使用原始数据表的行号。
二、筛选
许多筛选工作都可以使用which函数完成,例如:
挑选出iris数据集中Sepal.Width为2的数据:
>iris[which(iris$Sepal.Width == 2), ] Sepal.Length Sepal.Width Petal.LengthPetal.Width Species 61 5 2 3.5 1 versicolor
挑选出iris数据集中Sepal.Width大于4的数据:
>iris[which(iris$Sepal.Width > 4), ] Sepal.Length Sepal.Width Petal.LengthPetal.Width Species 16 5.7 4.4 1.5 0.4 setosa 33 5.2 4.1 1.5 0.1 setosa 34 5.5 4.2 1.4 0.2 setosa
挑选出iris数据集中Species为setosa的数据:
iris[which(iris$Species== 'setosa'), ]
如果挑选Species为setosa或virginica的数据呢,当然我们可以用“或”的运算符“|”来构建:
iris[which((iris$Species== 'setosa') | (iris$Species == 'virginica')), ]
但是我们推荐使用 %in% 操作符,a %in% b 将生成一个与a长度相同的logical序列,依次判断a中的元素是否被包含在b中。因此,上面的筛选问题可以使用 %in% 操作符解决:
iris[which(iris$Species%in% c('setosa', 'virginica')), ]
当然,不使用which,直接使用which内的判别式作为索引因也可以达到相同的筛选目的:
iris[iris$Sepal.Width== 2, ] iris[iris$Sepal.Width> 4, ] iris[iris$Species== 'setosa', ] iris[(iris$Species== 'setosa') | (iris$Species == 'virginica'), ] iris[iris$Species%in% c('setosa', 'virginica'), ]
同样,dplyr包也可以进行筛选操作,需使用filter函数。
filter(iris,Sepal.Width == 2) filter(iris,Sepal.Width > 4) filter(iris,Species == 'setosa') filter(iris,Species %in% c('setosa', 'virginica'))
三、分类汇总
假如我们要对iris数据集进行分类汇总,比方说计算不同Species中Sepal.Width的平均值。
第一种思路是使用split函数和sapply函数,首先将序列Sepal.Width按照Species划分成子集,然后对每个子集求平均:
-
>a <- split(iris$Sepal.Width, iris$Species)
-
>sapply(a, mean)
-
setosa versicolor virginica
-
3.428 2.770 2.974
split(x, f,drop = FALSE, ...)
x 要进行划分的数据
f 划分的依据,可以是list,表示按list中各变量的Level组合来划分
drop 默认为FALSE,若为TRUE,当f为list时,各变量的Level组合为空时自动舍弃这一分组
第二种思路是使用aggregate函数:
aggregate(x,by, FUN, ..., simplify = TRUE, drop = TRUE)
x 要分类汇总的数据,可以是各种形式,包括公式形式
by 分类依据,必须是list形式
FUN 汇总使用的函数
simplify 默认为TRUE,表示汇总结果以简化形式表现
drop 默认为TRUE,表示不存在的Level组合自动舍弃
> aggregate(x = iris$Sepal.Width, by= list(iris$Species), FUN = mean) Group.1 x 1 setosa 3.428 2 versicolor 2.770 3 virginica 2.974 > aggregate(x = iris[, 1:2], by =list(iris$Species), FUN = mean) Group.1 Sepal.Length Sepal.Width 1 setosa 5.006 3.428 2 versicolor 5.936 2.770 3 virginica 6.588 2.974