问题1:比如两个变量i,j
i=1:4 j=1:30
公式y=j+10i
计算出的y是矩阵
这个循环该怎么写呢?
解:
i <- 1:4; j <- 1:30; # i and j
ni<- length(i); nj <- length(j) # lengths of i and j
y <- matrix(NA, nj, ni) # initiate a matrix with nj rows and ni columns
for (k in 1:ni){
for (p in 1:nj){
y [p, k] <- i[k] * 10 + j[p] # fill the matrix
}
}
一个更简洁的方法:
matrix(rep(i, each=nj) * 10+rep(j, ni), nj, ni)
问题2
例子1
## if与条件判断
fun.test <- function(a, b, method = "add"){
if(method == "add") { ## 如果if或者for/while;
res <- a + b ## 等后面的语句只有一行,则无需使用花括号。
}
if(method == "subtract"){
res <- a - b
}
return(res) ## 返回值
}
### 检验结果
fun.test(a = 10, b = 8, method = "add")
fun.test(a = 10, b = 8, method = "substract")
for循环有些时候是必须要用到的,for循环内部,往往需要用下标,访问数据内的一定元素,例如向量内的元素,这时候用方括号表示。一维的数据组合,或者数组,常常称为向量。二维的数据组合,往往称为矩阵,或者数据框。具体的访问方式主要是方括号内部有没有逗号的区别。for循环或者while循环有时候让人觉得比较困惑,可能需要专门的时间进行讲解。
例2
### for循环与算法
test.sum <- function(x)
{
res <- 0 ### 设置初始值,在第一次循环的时候使用
for(i in 1:length(x)){
res <- res + x ## 这部分是算法的核心,
##总是总右面开始计算,结果存到左边的对象
}
return(res)
}
### 检验函数
a <- c(1,2,1,6,1,8,9,8)
test.sum(a)
sum(a)
无论是什么样的函数,算法才是最关键的。往往需要巧妙得设计算法,让函数快捷高效。
(3). 返回值。
返回值就是函数给出的结果。打个比方,编写一个函数,就像自己攒一个机器,例如现在攒好 一台豆浆机,该豆浆机要求输入大豆,输入的大豆就是参数, 返回的结果,就是豆浆。如果该豆浆机需要不停地输入大豆, 而不能产出豆浆,这样的机器就一定会被扔掉。函数也是一样的, 需要给出返回值。 R中默认的情况是将最后一句作为返回值。但是为了函数的可读性起见,应该尽量指名返回值。返回值用return()函数给出。 函数在内部处理过程中,一旦遇到return(),就会终止运行, 将return()内的数据作为函数处理的结果给出。
下面举例说明R函数的编写方法。
例3 计算标准差
sd2 <- function(x)
{
# 异常处理,当输入的数据不是数值类型时报错
if(!is.numeric(x)){
stop("the input data must be numeric!\n")
}
# 异常处理,当仅输入一个数据的时候,告知不能计算标准差
if(length(x) == 1){
stop("can not compute sd for one number,
a numeric vector required.\n")
}
## 初始化一个临时向量,保存循环的结果,
## 求每个值与平均值的平方
x2 <- c()
## 求该向量的平均值
meanx <- mean(x)
## 循环
for(i in 1:length(x)){
xn <- x - meanx
x2 <- xn^2
}
## 求总平方和
sum2 <- sum(x2)
# 计算标准差
sd <- sqrt(sum2/(length(x)-1))
# 返回值
return(sd)
}
## 程序的检验
## 正常的情况
sd2(c(2,6,4,9,12))
## 一个数值的情况
sd2(3)
## 输入数据不为数值类型时
sd2(c("1", "2"))
问题3
今天在做一个项目的时候发现R剔除重复值比较困难,百度之后找到了解决办法:如果有下列的数据
> a
公司 比例
1 a 0.4
2 a 0.3
3 a 0.2
4 b 0.5
5 b 0.4
如果想仅保留每个公司的第一条数据,可使用如下方法
> duplicated(a$公司)
[1] FALSE TRUE TRUE FALSE TRUE
> b<-duplicated(a$公司)
> a[!b,]
公司 比例
1 a 0.4
4 b 0.5
如果是要完全去重呢?也就是去除公司和比例完全一样的行数据,则用如下方法:
> duplicated(paste(a$公司,a$比例))
[1] FALSE FALSE FALSE FALSE FALSE
> a[!duplicated(paste(a$公司,a$比例)),]
公司 比例
1 a 0.4
2 a 0.3
3 a 0.2
4 b 0.5
5 b 0.4
问题4
R语言中的循环函数(Grouping Function) R语言中有几个常用的函数,可以按组对数据进行处理,apply, lapply, sapply, tapply, mapply,等。这几个函数功能有些类似,下面介绍下这几个函数的用法。
Apply
这是对一个Matrix或者Array进行某个维度的运算。其格式是:
Apply(数据,维度Index,运算函数,函数的参数)
对于Matrix来说,其维度值为2,第二个参数维度Index中,1表示按行运算,2表示按列运算。下面举一个例子:
m<-matrix(1:6,2,3)
构建一个简单的2行3列的矩阵,内容为:
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
如果我们要计算每一行的sum值,那么我们可以写为:apply(m,1,sum)[1] 9 12如果要计算每一列的mean值,那么改为:apply(m,2,mean)[1] 1.5 3.5 5.5假如某个值为NA,那么要忽略NA值,进行每一行的SUM怎么办呢?m[2,2]<-NA [,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 NA 6
apply(m,1,sum)
[1] 9 NA 本身sum函数有一个参数na.rm,我们可以将这个参数带人到apply函数中,作为第4个参数:apply(m,1,sum,na.rm=TRUE)
[1] 9 8 需要注意的是如果是Data Frame,那么系统会将其转为Matrix,如果所有Column不是数字类型或者类型不一致,导致转换失败,那么apply是运算不出任何一列的结果的。Lapply
前面说到apply是对于matrix和array的,针对list,我们可以使用lapply函数。该函数接收list,返回的结果也是一个list。其调用如下:Apply(数据,运算函数,函数的参数)对于Data Frame来说,如果不同的列有不同的数据类型,不能转换成Matrix,但是却可以转换成List,然后使用lapply函数。我们建立一个学生名字,年龄和成绩的Data Frame,然后统计平均年龄和平均成绩,由于name列不是数值类型,所以无法算平均值,所以我们可以对非数值的数据只取count数量。这里就需要用到自定义函数。函数可以是匿名函数,也可以是之前定义好的函数,由于这里逻辑简单,我们可以用匿名函数解决。s<-data.frame(name=c("Devin","Edward","Lulu"),age=c(30,33,29),score=c(95,99,90))
name age score
1 Devin 30 95
2 Edward 33 99
3 Lulu 29 90
lapply(s,function(x){if(is.numeric(x)){mean(x)}else{length(x)}})
$name
[1] 3
$age
[1] 30.66667
$score
[1] 94.66667我们可以看到返回了一个List的结果,里面包含3个项,每个项是函数执行的结果。lapply返回的结果和传入的List的结构相同,传入多少个Item,返回的也是多少个Item。Sapply
Sapply函数和Lapply函数很类似,也是对List进行处理,只是在返回结果上,Sapply会根据结果的数据类型和结构,重新构建一个合理的数据类型返回。调用格式如下:Apply(数据,运算函数,函数的参数,simplify = TRUE, USE.NAMES = TRUE)对于其中的simplify参数,就是指明是否对返回的结果集重新组织,如果为FALSE,那么就相当于lapply了。{if(is.numeric(x)){mean(x)}else{length(x)}})
name age score
3.00000 30.66667 94.66667