首页 > 代码库 > r 数据分组处理

r 数据分组处理

一、R语言实现数据的分组求和

实验数据集 姓名,年龄,班级 ,成绩, 科目

 

[html] view plain copy
 
 技术分享技术分享
  1. student <- data.frame (  
  2.   name = c("s1", "s2", "s3", "s2", "s1", "s3"),  
  3.   age = c(12, 13, 10, 13, 12, 10),  
  4.   classid = c("c1", "c2", "c3", "c2", "c1", "c3"),  
  5.   score = c(78, 68, 99, 81, 82, 90),  
  6.   subject = c("su1", "su1", "su1", "su2", "su2", "su2")  
  7. )  

下面看看 students 的结构

 

 

[html] view plain copy
 
 技术分享技术分享
  1. > str(students)  
  2. ‘data.frame‘:   6 obs. of  5 variables:  
  3.  $ name   : Factor w/ 3 levels "s1","s2","s3": 1 2 3 2 1 3  
  4.  $ age    : num  12 13 10 13 12 10  
  5.  $ classid: Factor w/ 3 levels "c1","c2","c3": 1 2 3 2 1 3  
  6.  $ score  : num  78 68 99 81 82 90  
  7.  $ subject: Factor w/ 2 levels "su1","su2": 1 1 1 2 2 2  

可以看到,在调用 data.frame 函数之后,默认将字符形变量转换成了因子变量,并且重新对它们进行编码

 

下面我们求每个班级平均成绩:用SQL语句如下

 

[html] view plain copy
 
 技术分享技术分享
  1. select count(score) from students group by subject  

用R自带的函数 tapply 也可以实现上面的要求:

 

 

[html] view plain copy
 
 技术分享技术分享
  1. > tapply(student$score, students$subject, sum)  
  2. su1 su2   
  3. 245 253   

从tapply的执行结果我们可以看出,tapply 是根据第二个变量因子变量(注意必须是因子变量)对第一个变量来分组,然后对所有分成的小组调用最后的函数

 

 

再来看一个例子,加深对因子的理解:

 

[html] view plain copy
 
 技术分享技术分享
  1. > affils <- c("R", "D", "D", "R", "U", "D")  
  2. > affils <- as.factor(x = affils)  
  3. > affils  
  4. [1] R D D R U D  
  5. Levels: D R U  
  6. > affils <- factor(affils, ordered = TRUE)  
  7. > affils  
  8. [1] R D D R U D  
  9. Levels: D U  
  10. > affils <- factor(affils, levels = c("U", "R", "D"),  ordered = TRUE)  
  11. > tapply(ages, affils, mean)  
  12.  U  R  D   
  13. 21 31 41   
  14. > ages <- c(25, 26, 55, 37, 21, 42)  
  15. > affils <- c("R", "D", "D", "R", "U", "D")  
  16. > affils <- as.factor(x = affils)  
  17. > affils  
  18. [1] R D D R U D  
  19. Levels: D R U  
  20. > affils <- factor(affils, ordered = TRUE)  
  21. > affils  
  22. [1] R D D R U D  
  23. Levels: D U  
  24. > affils <- factor(affils, levels = c("U", "R", "D"),  ordered = TRUE)  
  25. > affils  
  26. [1] R D D R U D  
  27. Levels: U D  
  28. > tapply(ages, affils, mean)  
  29.  U  R  D   
  30. 21 31 41   

从例子中可以发现,因子的水平,以及水平的高低我们都是可以按照自己的想法去控制的

 

 

好了,有了上面的基础知识,下面进一步加大难度,如果分组变量有几个呢?

请看下面的例子:

实验数据如下:

 

[html] view plain copy
 
 技术分享技术分享
  1. > staff <- data.frame(list(gender = c("M", "M", "F", "M", "F", "F"),  
  2. +                      age = c(47, 59, 21, 32, 33, 24),  
  3. +                      income = c(55000, 88000, 32450, 76500, 123000, 45650)  
  4. +                      )  
  5. +                 )  
  6. > staff  
  7.   gender age income  
  8. 1      M  47  55000  
  9. 2      M  59  88000  
  10. 3      F  21  32450  
  11. 4      M  32  76500  
  12. 5      F  33 123000  
  13. 6      F  24  45650  
  14. > str(staff)  
  15. ‘data.frame‘:   6 obs. of  3 variables:  
  16.  $ gender: Factor w/ 2 levels "F","M": 2 2 1 2 1 1  
  17.  $ age   : num  47 59 21 32 33 24  
  18.  $ income: num  55000 88000 32450 76500 123000 ...  

下面分析:年龄大于 25 的不同性别的总收入,以及年龄小于 25 的不同性别的总收入

 

 

 

[html] view plain copy
 
 技术分享技术分享
  1. > staff$over25 <- ifelse(staff$age > 25, 1, 0)  
  2. > staff  
  3.   gender age income over25  
  4. 1      M  47  55000      1  
  5. 2      M  59  88000      1  
  6. 3      F  21  32450      0  
  7. 4      M  32  76500      1  
  8. 5      F  33 123000      1  
  9. 6      F  24  45650      0  
  10. > tapply(staff$income, list(staff$gender, staff$over25), sum)  
  11.       0      1  
  12. F 78100 123000  
  13. M    NA 219500  

从结果中可以清楚的看到,年龄小于 25 的女员工总收入为 78100, 其他的同理可以分析出来

 

二、如果你只是想分组呢?那么你就要要用到 spit 函数,注意字符串的分割是用 strsplit, 下面看如下两个例子就清楚明了了

 

[html] view plain copy
 
 技术分享技术分享
  1. > split(staff$income, list(staff$over25, staff$gender))  
  2. $`0.F`  
  3. [1] 32450 45650  
  4.   
  5. $`1.F`  
  6. [1] 123000  
  7.   
  8. $`0.M`  
  9. numeric(0)  
  10.   
  11. $`1.M`  
  12. [1] 55000 88000 76500  
  13.   
  14. > split(staff$income, list(staff$gender, staff$over25))  
  15. $F.0  
  16. [1] 32450 45650  
  17.   
  18. $M.0  
  19. numeric(0)  
  20.   
  21. $F.1  
  22. [1] 123000  
  23.   
  24. $M.1  
  25. [1] 55000 88000 76500  

从上面的例子我们可以非常清楚的明白 split 函数的工作原理

 

下面看一个有意思的例子,利用 split 迅速定位上面男性的下标,一种非常自然的想法是排序,然后如果数据总是变化无常怎么定位我们想要的那一类数据的下标呢?

 

[html] view plain copy
 
 技术分享技术分享
  1. > split(1:length(staff$gender), staff$gender)  
  2. $F  
  3. [1] 3 5 6  
  4.   
  5. $M  
  6. [1] 1 2 4  

 

如果我们将这个方法与文本挖掘联想到一起,我们可以发现,这个方法可以非常容易的解决英文文本词汇索引的问题:

如果给你一个文本文件,假设单词都是按照空格分割,现在要统计哪些单词出现在文本中,以及出现的位置和次数,我们可以用下面的方法非常容易的解决

 

 

[html] view plain copy
 
 技术分享技术分享
  1. filewords <- function(tf) {  
  2.   txt <- scan(tf, "")  
  3.   words <- split(1:length(txt), txt)  
  4.   return(words)  
  5. }  

另外我们应该关注 by() 函数的使用

 

最后一句话:在R中如果可以不使用循环则力求不使用

 
0

r 数据分组处理