Chapter 05—Advanced data management(Part 1)
一. R的数学函数,统计函数及字符处理函数
例01:一道实际应用题
一组学生其数学,科学和英语的成绩如下表:

任务:根据成绩,决定对每个学生的单独指导;
前20%的学生的成绩为A,次之为B,以此类推;
把学生姓名按照字母表顺序排序。
问题:三科考试的分数不具可比性;必须把考试分数转化为可以比较的记分单元,然后才能进行分数间的比较。
为分配A,B等级,需把学生成绩转换为百分比形式。
姓名有单独的域,使得分配学生的任务变得更难;故应该把名字分为名和姓。
1. 数字和字符函数(Numerical(mathematical+statistical+probability) and character functions)
(1)数学函数(mathematical functions)
例02:常用的数学函数
> abs(-4) [1] 4 > sqrt(25) [1] 5 > ceiling(3.475) [1] 4 > floor(5.99) [1] 5 > trunc(5.99) [1] 5 > round(3.475,digits=2) [1] 3.48 > signif(3.475,digits=2) [1] 3.5 > cos(60) [1] -0.952413 > sin(60) [1] -0.3048106 > tan(60) [1] 0.3200404 > acos(-0.952413) [1] 2.831853 > asin(-0.3048106) [1] -0.3097396 > atan(0.3200404) [1] 0.3097396 > cosh(2) [1] 3.762196 > sinh(2) [1] 3.62686 > tanh(2) [1] 0.9640276 > acosh(3.762196) [1] 2 > asinh(3.62686) [1] 2 > atanh(0.9640276) [1] 2 > log10(10) [1] 1 > log(10) [1] 2.302585 > exp(2.3026) [1] 10.00015
(2)统计函数(statistical functions)


例03:常用的统计函数
> mean(c(1,2,3,4)) [1] 2.5 > median(c(1,2,3,4)) [1] 2.5 > sd(c(1,2,3,4)) [1] 1.290994 > var(c(1,2,3,4)) [1] 1.666667 > mad(c(1,2,3,4)) [1] 1.4826 > x<-c(1,2,3,4) > range(x) [1] 1 4 > diff(range(x)) [1] 3 > > sum(1,2,3,4) [1] 10 > > x<-c(1,5,23,29) > diff(x) [1] 4 18 6 > > min(c(1,2,3,4)) [1] 1 > max(c(1,2,3,4)) [1] 4
例04:计算平均值和标准差
> x<-c(1,2,3,4,5,6,7,8) >
> mean(x) [1] 4.5 > sd(x) [1] 2.44949 >
> n<-length(x) > meanx<-sum(x)/n > css<-sum((x-meanx)^2) > sdx<-sqrt(css/(n-1)) > meanx [1] 4.5 > sdx [1] 2.44949
A)为标准化每一列的暂定平均数(arbitrary mean)和标准差(standard deviation),可以使用下面格式的代码:
newdata<-scale(mydata)*SD+M
其中,M是期待的均值,SD是期待的标准差。
注意:scale()在非数值的列中使用,会产生错误。
B)标准化某一特定的列,而非一个矩阵或数据帧,则可以使用下面的代码:
newdata<-transform(mydata,myvar=scale(myvar)*10+50)
·标准化myvar,使其为一个平均值为50,标准差为10的变量。
(3)概率函数(probability functions)
在R中,概率函数的形式如下:
[dpqr]=distribution_abbreviation()
·d=dentity, p=distribution function, q=quantile function, r=random generation(random deviates)
常见的概率分布如下图:

例05:从均匀分布产生一个随机数
·set.seed()函数:明确的指定种子,使求为随机数的结果,多次重复仍可得到;
·runif()函数:在均匀分布上,产生0到1之间的伪随机数。
> runif(5) [1] 0.1476982 0.4830784 0.2800061 0.9300127 0.7477501 > runif(5) [1] 0.6784092 0.9378730 0.1152914 0.5070802 0.1728310 > set.seed(1234) > runif(5) [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154 > set.seed(1234) > runif(5) [1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154
例06:从多元正态分布中产生数据
mvnorm()函数:在MASS包中;从多元正态分布中取来自于平均值向量和协方差矩阵中取数据。
mvnorm(n,mean,sigma)
·n:希望的样例大小(desired sample size);
·mean:平均值的向量(mean vector);
·sigma:协方差矩阵(variance-covariance matrix)。

> library(MASS) > options(digits=3) > set.seed(1234) >
> mean<-c(230.7,146.7,3.6) > sigma<-matrix(c(15360.8,6721.2,-47.1,6721.2,4700.9,-16.5,-47.1,-16.5,0.3),nrow=3,ncol=3) >
> mydata<-mvrnorm(500,mean,sigma) > mydata<-as.data.frame(mydata) > names(mydata)<-c("y","x1","x2") >
> dim(mydata) [1] 500 3 > head(mydata,n=10) y x1 x2 1 434.9 286.6 2.57 2 61.4 69.1 4.32 3 142.0 108.5 3.37 4 182.1 72.8 3.52 5 165.1 185.1 3.15 6 167.2 160.3 3.27 7 258.2 233.6 3.41 8 84.3 54.2 4.10 9 158.5 130.7 3.94 10 131.8 176.8 4.43 >
A)set.seed(1234):设置一个随机数种子;
B)特例化平均值向量为mean,协方差矩阵为sigma;
C)产生500个伪随机数的观测量(pseudo-random observations),用mydata保存;
D)为了方便,用dim()函数,把结果从矩阵转换为数据帧,并且用head()函数,为变量赋一个名字。
(4)字符函数(character functions)
数学函数和统计函数对数值型数据处理,字符函数对文本型数据进行处理。


例07:字符函数的小例子
> x<-c("ab","cde","fghij") > length(x) [1] 3 > nchar(x) [1] 2 3 5 > nchar(x[3]) [1] 5 >
> x<-"abcdef" > substr(x,2,4) [1] "bcd" > substr(x,2,4)<-"22222" > x [1] "a222ef" >
> grep("A",c("b","A","c"),fixed=TRUE) [1] 2 > > sub("\\s",".","Hello There") [1] "Hello.There" >
> y<-strsplit("abc","") > y [[1]] [1] "a" "b" "c"
> paste("x",1:3,sep="") [1] "x1" "x2" "x3" > paste("x",1:3,sep="M") [1] "xM1" "xM2" "xM3" > paste("Today is",date()) [1] "Today is Thu Aug 01 08:03:33 2013" >
> toupper("abc") [1] "ABC" >
> tolower("ABC") [1] "abc" >
(5)其他函数

例08:其他函数的例子
> x<-c(2,5,6,9) > length(x) [1] 4 >
> indices<-seq(1,10,2) > indices [1] 1 3 5 7 9 >
> y<-rep(1:3,2) > y [1] 1 2 3 1 2 3 >
> firstname<-c("Jane") > cat("Hello",firstname,"\n") Hello Jane >
> name<-"Bob" > cat("Hello",name,"\b.\n","Isn\'t R","\t","GREAT?\n") Hello Bob. Isn't R GREAT?
例09:apply函数的例子
> mydata<-matrix(rnorm(30),nrow=6) > mydata [,1] [,2] [,3] [,4] [,5] [1,] -1.70058013 -0.04791481 1.8256761 0.18096362 0.747712227 [2,] 0.61948876 0.08585212 1.0945512 0.37603502 0.002217611 [3,] 0.05312635 -0.22062291 -0.4759186 0.17347971 0.764638370 [4,] -0.72229860 0.58144854 -1.1961967 -0.07836057 0.342189978 [5,] -0.68587492 -0.93605640 -2.8959270 1.08664460 0.205011102 [6,] 0.10207794 -0.80774063 0.9329347 0.44210056 0.360341446 > apply(mydata,1,mean) [1] 0.20117141 0.43562895 0.05894057 -0.21464346 -0.64524053 0.20594280 > apply(mydata,2,mean) [1] -0.3890101 -0.2241723 -0.1191467 0.3634772 0.4036851 > apply(mydata,2,mean,trim=2) [1] -0.3163743 -0.1342689 0.2285080 0.2784993 0.3512657 > apply(mydata,2,mean,trim=0.2) [1] -0.31324231 -0.24760656 0.08884265 0.29314473 0.41381369
apply()函数:在数组的边缘使用一个函数;
lapply()函数,sapply()函数:对表使用一个函数。
apply(x,MARGIN,FUN,...)
·x:数据对象;
·MARGIN:索引的维度(dimension index);
·FUN:指定的函数;
·.......:传给函数的参数。
2. 例01的解决办法
(1)输入表中的数据

> options(digits=2) > Students<-c("John Davis","Angela Williams","Bullwinkle Moose","David Jones","Janice Markhammer","Cheryl Cushing","Reuven Ytzrhak","Greg Knox","Joel England","Mary Rayburn") > Math<-c(502,600,412,358,495,512,410,625,573,522) > Science<-c(95,99,80,82,75,85,80,95,89,86) > English<-c(25,22,18,15,20,28,15,30,27,18) > roster<-data.frame(Students,Math,Science,English,stringAsFactors=FALSE) > roster Students Math Science English stringAsFactors 1 John Davis 502 95 25 FALSE 2 Angela Williams 600 99 22 FALSE 3 Bullwinkle Moose 412 80 18 FALSE 4 David Jones 358 82 15 FALSE 5 Janice Markhammer 495 75 20 FALSE 6 Cheryl Cushing 512 85 28 FALSE 7 Reuven Ytzrhak 410 80 15 FALSE 8 Greg Knox 625 95 30 FALSE 9 Joel England 573 89 27 FALSE 10 Mary Rayburn 522 86 18 FALSE
options(digits=2):小数点后仅保留2位数字。
(2)因为数学,科学和英语都是用不同的范围来表示的,需使这三种成绩可以比较。一种较常用的方法就是:标准化变量,使数据表现为标准差的形式。scale()函数。
z<-scale(roster[,2:4]) > z Math Science English [1,] 0.013 1.078 0.587 [2,] 1.143 1.591 0.037 [3,] -1.026 -0.847 -0.697 [4,] -1.649 -0.590 -1.247 [5,] -0.068 -1.489 -0.330 [6,] 0.128 -0.205 1.137 [7,] -1.049 -0.847 -1.247 [8,] 1.432 1.078 1.504 [9,] 0.832 0.308 0.954 [10,] 0.243 -0.077 -0.697 attr(,"scaled:center") Math Science English 501 87 22 attr(,"scaled:scale") Math Science English 86.7 7.8 5.5
(3)通过计算每个同学的平均分,即每行的平均数,来衡量一个学生表现的好坏。用到mean()函数和cbind()函数。
> score<-apply(z,1,mean) > score [1] 0.56 0.92 -0.86 -1.16 -0.63 0.35 -1.05 1.34 0.70 -0.18 > roster<-cbind(roster,score) > roster Students Math Science English stringAsFactors score 1 John Davis 502 95 25 FALSE 0.56 2 Angela Williams 600 99 22 FALSE 0.92 3 Bullwinkle Moose 412 80 18 FALSE -0.86 4 David Jones 358 82 15 FALSE -1.16 5 Janice Markhammer 495 75 20 FALSE -0.63 6 Cheryl Cushing 512 85 28 FALSE 0.35 7 Reuven Ytzrhak 410 80 15 FALSE -1.05 8 Greg Knox 625 95 30 FALSE 1.34 9 Joel England 573 89 27 FALSE 0.70 10 Mary Rayburn 522 86 18 FALSE -0.18
(4)quantile()函数给出每个学生的表现分数的百分比的排名。
> y<-quantile(roster$score,c(.8,.6,.4,.2)) > y 80% 60% 40% 20% 0.74 0.44 -0.36 -0.89
(5)使用逻辑操作符,在一个新的成绩变量的分类中,这需要在数据帧roster添加新的变量grade。
> roster$grade[score>=y[1]]<-"A" > roster$grade[score<y[1]&score>=y[2]]<-"B" > roster$grade[score<y[2]&score>=y[3]]<-"C" > roster$grade[score<y[3]&score>=y[4]]<-"D" > roster$grade[score<y[4]]<-"F" > roster Students Math Science English stringAsFactors score grade 1 John Davis 502 95 25 FALSE 0.56 B 2 Angela Williams 600 99 22 FALSE 0.92 A 3 Bullwinkle Moose 412 80 18 FALSE -0.86 D 4 David Jones 358 82 15 FALSE -1.16 F 5 Janice Markhammer 495 75 20 FALSE -0.63 D 6 Cheryl Cushing 512 85 28 FALSE 0.35 C 7 Reuven Ytzrhak 410 80 15 FALSE -1.05 F 8 Greg Knox 625 95 30 FALSE 1.34 A 9 Joel England 573 89 27 FALSE 0.70 B 10 Mary Rayburn 522 86 18 FALSE -0.18 C
(6)使用strsplit()函数:让一个向量返回一个表。在此题中,把学生的名和姓的中间的空格符去掉。
> name<-strsplit(roster$Students," ") Error in strsplit(roster$Students, " ") : non-character argument > is.character(roster$character) [1] FALSE > name<-strsplit(as.character(roster$Students)," ") > name [[1]] [1] "John" "Davis" [[2]] [1] "Angela" "Williams" [[3]] [1] "Bullwinkle" "Moose" [[4]] [1] "David" "Jones" [[5]] [1] "Janice" "Markhammer" [[6]] [1] "Cheryl" "Cushing" [[7]] [1] "Reuven" "Ytzrhak" [[8]] [1] "Greg" "Knox" [[9]] [1] "Joel" "England" [[10]] [1] "Mary" "Rayburn"
(7)sapply()函数:提取每个组合的第一个元素,放在名的数组中;提取每个组合的第二个元素,放在姓的数组中。
cbind()函数:把姓和名的数组添加到roster中。
删除roster中的Students这一列。
Firstname<-sapply(name,"[",1) > Lastname<-sapply(name,"[",2) > roster<-cbind(Firstname,Lastname,roster[,-1]) > roster Firstname Lastname Math Science English stringAsFactors score grade 1 John Davis 501 95 25 FALSE 0.56 B 2 Angela Williams 600 99 22 FALSE 0.92 A 3 Bullwinkle Moose 412 80 18 FALSE -0.86 D 4 David Jones 358 82 15 FALSE -1.16 F 5 Janice Markhammer 495 75 20 FALSE -0.63 D 6 Cheryl Cushing 512 85 28 FALSE 0.35 C 7 Reuven Ytzrhak 410 80 15 FALSE -1.05 F 8 Greg Knox 625 95 30 FALSE 1.34 A 9 Joel England 573 89 27 FALSE 0.70 B 10 Mary Rayburn 522 86 18 FALSE -0.18 C
(8)通过Firstname和Lastname排列数据集roster
> roster[order(Lastname,Firstname),] Firstname Lastname Math Science English stringAsFactors score grade 6 Cheryl Cushing 512 85 28 FALSE 0.35 C 1 John Davis 501 95 25 FALSE 0.56 B 9 Joel England 573 89 27 FALSE 0.70 B 4 David Jones 358 82 15 FALSE -1.16 F 8 Greg Knox 625 95 30 FALSE 1.34 A 5 Janice Markhammer 495 75 20 FALSE -0.63 D 3 Bullwinkle Moose 412 80 18 FALSE -0.86 D 10 Mary Rayburn 522 86 18 FALSE -0.18 C 2 Angela Williams 600 99 22 FALSE 0.92 A 7 Reuven Ytzrhak 410 80 15 FALSE -1.05 F
浙公网安备 33010602011771号