注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

互联网产品经理的窝

梦想社:一个人为了梦想,始终没有停下自己的脚步

 
 
 

日志

 
 

R语言编程入门 B  

2013-05-14 16:22:02|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

V. 向量化运算

 

和matlab一样,R语言以向量为基本运算对象。也就是说,当输入的对象为向量时,对其中的每个元素分别进行处理,然后以向量的形式输出。R语言中基本上所有的数据运算均能允许向量操作。不仅如此,R还包含了许多高效的向量运算函数,这也是它不同于其它软件的一个显著特征。向量化运算的好处在于避免使用循环,使代码更为简洁、高效和易于理解。本文来对apply族函数作一个简单的归纳,以便于大家理解其中的区别所在。

所谓apply族函数包括了apply,sapply,lappy,tapply等函数,这些函数在不同的情况下能高效的完成复杂的数据处理任务,但角色定位又有所不同。

 

apply()函数的处理对象是矩阵或数组,它逐行或逐列的处理数据,其输出的结果将是一个向量或是矩阵。下面的例子即对一个随机矩阵求每一行的均值。要注意的是apply与其它函数不同,它并不能明显改善计算效率,因为它本身内置为循环运算。

1m.data <- matrix(rnorm(100),ncol=10)
2apply(m.data,1,mean)

lappy()的处理对象是向量、列表或其它对象,它将向量中的每个元素作为参数,输入到处理函数中,最后生成结果的格式为列表。在R中数据框是一种特殊的列表,所以数据框的列也将作为函数的处理对象。下面的例子即对一个数据框按列来计算中位数与标准差。

1f.data <- data.frame(x=rnorm(10),y=runif(10))
2lapply(f.data,FUN=function(x) list(median=median(x),sd=sd(x))


sapply()可能是使用最为频繁的向量化函数了,它和lappy()是非常相似的,但其输出格式则是较为友好的矩阵格式。

1sapply(f.data,FUN=function(x)list(median=median(x),sd=sd(x)))
2class(test)

tapply()的功能则又有不同,它是专门用来处理分组数据的,其参数要比sapply多一个。我们以iris数据集为例,可观察到Species列中存放了三种花的名称,我们的目的是要计算三种花瓣萼片宽度的均值。其输出结果是数组格式。

 

1head(iris)
2attach(iris)
3tapply(Sepal.Width,INDEX=Species,FUN=mean)

与tapply功能非常相似的还有aggregate(),其输出是更为友好的数据框格式。而by()和上面两个函数是同门师兄弟。

另外还有一个非常有用的函数replicate(),它可以将某个函数重复运行N次,常常用来生成较复杂的随机数。下面的例子即先建立一个函数,模拟扔两个骰子的点数之和,然后重复运行10000次。

1game <- function() {
2n <- sample(1:6,2,replace=T)
3return(sum(n))
4}
5replicate(n=10000,game())

最后一个有趣的函数Vectorize(),它能将一个不能进行向量化运算的函数进行转化,使之具备向量化运算功能。

 

VI. 循环与条件

 

循环

for (n in x) {expr}

R中最基本的是for循环,其中n为循环变量,x通常是一个序列。n在每次循环时从x中顺序取值,代入到后面的expr语句中进行运算。下面的例子即是以for循环计算30个Fibonacci数。

1x <- c(1,1)
2for (i in 3:30) {
3x[i] <- x[i-1]+x[i-2]
4}

while (condition) {expr}

当不能确定循环次数时,我们需要用while循环语句。在condition条件为真时,执行大括号内的expr语句。下面即是以while循环来计算30个Fibonacci数。

1x <- c(1,1)
2i <- 3
3while (i &lt;= 30) {
4x[i] <- x[i-1]+x[i-2]
5i <- i +1
6}

条件

if (conditon) {expr1} else {expr2}

if语句用来进行条件控制,以执行不同的语句。若condition条件为真,则执行expr1,否则执行expr2。ifesle()函数也能以简洁的方式构成条件语句。下面的一个简单的例子是要找出100以内的质数。

1x <- 1:100
2y <- rep(T,100)
3for (i in 3:100) {
4if (all(i%%(2:(i-1))!=0)){
5y[i] <- TRUE
6else {y[i] <- FALSE
7}
8}
9print(x[y])

在上面例子里,all()函数的作用是判断一个逻辑序列是否全为真,%%的作用是返回余数。在if/else语句中一个容易出现的错误就是else没有放在}的后面,若你执行下面的示例就会出现错误。

1logic = 3
2x<- c(2,3)
3if (logic == 2){
4y <- x^2
5}
6else {
7y<-x^3
8}
9show(y)

一个例子

本例来自于"introduction to Scientific Programming and Simulatoin Using R"一书的习题。有这样一种赌博游戏,赌客首先将两个骰子随机抛掷第一次,如果点数和出现7或11,则赢得游戏,游戏结束。如果没有出现7或11,赌客继续抛掷,如果点数与第一次扔的点数一样,则赢得游戏,游戏结束,如果点数为7或11则输掉游戏,游戏结束。如果出现其它情况,则继续抛掷,直到赢或者输。用R编程来计算赌客赢的概率,以决定是否应该参加这个游戏。

01craps <- function() {
02#returns TRUE if you win, FALSE otherwise
03initial.roll <- sum(sample(1:6,2,replace=T))
04if (initial.roll == 7 || initial.roll == 11) return(TRUE)
05while (TRUE) {
06current.roll <- sum(sample(1:6,2,replace=T))
07if (current.roll == 7 || current.roll == 11) {
08return(FALSE)
09else if (current.roll == initial.roll) {
10return(TRUE)
11}
12}
13}
14mean(replicate(10000, craps()))

从最终结果来看,赌客赢的概率为0.46,长期来看只会往外掏钱,显然不应该参加这个游戏了。最后要说的是,本题也可以用递归来做。

 

VII. 程序查错

写程序难免会出错,有时候一个微小的错误需要花很多时间来调试程序来修正它。所以掌握必要的调试方法能避免很多的无用功。

基本的除错方法是跟踪重要变量的赋值情况。在循环或条件分支代码中加入显示函数能完成这个工作。例如cat('var',var,'\n')。在确认程序运行正常后,可以将这行代码进行注释。好的编程风格也能有效的减少出错的机会。在编写代码时先写出一个功能最为简单的功能,然后在此基础上逐步添加其它复杂的功能。对输出结果进行绘图或统计汇总也能揭示一些潜在的问题。

另一种避免出错的方法是尽量使用函数。使用函数能将一个大的程序分解成几个小型的模块。一个函数模块只负责实现某一种功能的实现。这样容易理解程序,而且容易针对各函数的输入、计算、输出分别进行查错调试。R语言中函数的运行不会影响到全局变量,所以使用函数基本上不会有什么副作用。

但是在使用函数时需要注意的问题是输入参数的不可预测性。未预料到的输入参数会产生奇怪的或是错误的输出,所以在函数起始部分就要用条件语句来检查参数的正确与否。如果输入参数不正确,可以用下面的语句来停止程序执行stop('your message here.')

对函数进行调试的重要工具是browser(),它可以使我们进入调试模式逐行运行代码。在函数中的某一行插入browser()后,在函数执行时会在这一行暂停中断,并显示一个提示符。此时我们可以在提示符后输入任何R语言的交互式命令进行检查调试。输入n则会逐行运行程序,并提示下一行将运行的语句。输入c会直接跳到下一个中断点。而输入Q则会直接跟出调试模式。

debug()函数和browser()是相似的,如果你认为某个函数,例如fx(x),有问题的话,使用debug(fx(x))即可进入调试模式。它本质上是在函数的第一行加入了browser,所以其它提示和命令都是相同的。其它与程序调试有关的函数还包括:trace(),setBreakpoint(),traceback(),recover()


  评论这张
 
阅读(1397)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017