R语言Lecture5程序设计

上传人:E**** 文档编号:91252397 上传时间:2019-06-26 格式:PPT 页数:43 大小:358.50KB
返回 下载 相关 举报
R语言Lecture5程序设计_第1页
第1页 / 共43页
R语言Lecture5程序设计_第2页
第2页 / 共43页
R语言Lecture5程序设计_第3页
第3页 / 共43页
R语言Lecture5程序设计_第4页
第4页 / 共43页
R语言Lecture5程序设计_第5页
第5页 / 共43页
点击查看更多>>
资源描述

《R语言Lecture5程序设计》由会员分享,可在线阅读,更多相关《R语言Lecture5程序设计(43页珍藏版)》请在金锄头文库上搜索。

1、实验目的,实验内容,学习S语言中程序设计方法,1、程序设计方法 2、应用实例 3、实验作业,第五讲 程序设计,程序控制结构,S是一个表达式语言,其任何一个语句都可以看成是一个表达式。表达式之间以分号分隔或用换行分隔。表达式可以续行,只要前一行不是完整表达式(比如末尾是加减乘除等运算符,或有未配对的括号)则下一行为上一行的继续。 若干个表达式可以放在一起组成一个复合表达式,作为一个表达式使用。组合用大括号表示,如: x x S语言也提供了其它高级程序语言共有的分支、循环等程序控制结构。,分支结构,分支结构包括if结构: if (条件) 表达式1 或 if (条件) 表达式1 else 表达式2

2、其中的“条件”为一个标量的真或假值,表达式可以是用大括号包围的复合表达式。有else 子句时一般写成: if(条件) 表达式组 else 表达式组 这样的写法可以使else不至于脱离前面的if。,例如,如果变量lambda为缺失值就给它赋一个缺省值,可用: if(is.na(lambda) lambda 0) 注意“&”表示“与”,它是一个短路运算符,即第一个条件为假时就不计算第二个条件。如果不这样此例中计算对数就可以有无效值。 在条件中也可以用“|”(两个连续的竖线符号)表示“或”,它也是短路运算符,当第一个条件为真时就不再计算第二个条件。 “&” 、“|”只对标量适用,而“&” 、“|”适

3、用于向量,在用S编程序时一定要时刻牢记S是一个向量语言,几乎所有操作都是对向量进行的。而S中的if语句却是一个少见的例外,它的判断条件是标量的真值或假值。比如,我们要定义一个分段函数f(x),当x为正时返回1,否则返回0,马上可以想到用if语句实现如下: if(x0) 1 else 0 当x是标量时这个定义是有效的,但是当自变量x是一个向量时,比较的结果也是一个向量,这时条件无法使用。所以,这个分段函数应该这样编程: y= numeric(length(x) yx0 - 1 yx=0 - 0 有多个if语句时else与最近的一个配对。可以使用if . else if . else if . e

4、lse .的多重判断结构表示多分支。多分支也可以使用switch()函数。,循环结构,循环结构中常用的是for循环,是对一个向量或列表的逐次处理,格式为“for( name in values) 表达式”,如: for(i in seq(along=x) cat(x(, i, ) = , xi, n, sep=); s - s+xi; 这个例子我们需要使用下标的值,所以用seq(along=x)生成了x的下标向量。 如果不需要下标的值,可以直接如此使用: for(xi in x) cat(xi, n) s - s + xi ,当然,如果只是要求各元素的和,只要调用sum(x)即可。从这里我们也

5、可以看出,显式的循环经常是可以避免的,利用函数对每个元素计算值、使用sum等统计函数及apply、lapply 、sapply、tapply等函数往往可以代替循环。因为循环在S中是很慢的(S-PLUS和R都是解释语言),所以应尽量避免使用显式循环。 我们再举一个例子。比如,我们要计算同生日的概率。假设一共有365个生日(只考虑月、日),而且各生日的概率是相等的(这里忽略了闰年的情况以及可能存在的出生日期分布的不均匀)。设一个班有n个人,当n大于365时至少两个人生日相同是必然事件。当n小于等于365时,我们可以计算P至少有两人同生日= 1 - Pn个人生日彼此不同,这时,n个人的生日可取值数为

6、365n ,而n个人彼此不同的可能数为365中取n个的排列数,彼此不同的概率为P3n65 。因此,为了计算n1,2,.,364的情况下的同生日概率,可以用如下循环实现:, x = numeric(365) for(i in 1:365) xi= 1 for(j in 0:(i-1) xi= xi * (365-j)/365 xi x for(n in 1:365) xn =1 - prod(365:(365-n+1)/365) 这段程序只用了1秒。注意不能直接去计算365!,这会 超出数值表示范围。,另外要注意使用for(i in 1:n)格式的计数循环时要避免一个常见错误,即当n为零或负数时

7、1:n是一个从大到小的循环,而我们经常需要的是当n为零或负数时就不进入循环。为达到这一点,可以在循环外层判断循环结束值是否小于开始值。 while循环是在开始处判断循环条件的当型循环,如: While (b-aeps) c 0) b - c else a - c 是一段二分法解方程的程序。,还可以使用 repeat 表达式 循环,在循环体内用break跳出。 在一个循环体内用next表达式可以进入下一轮循环。 分支和循环结构主要用于定义函数。,S程序设计,对于复杂一些的计算问题我们应该编写成函数。这样做的好处是 编写一次可以重复使用,并且可以很容易地修改 函数内的变量名是局部的,运行函数不会使

8、函数内的局部变量被保存到当前的工作空间,可以避免在交互状态下直接赋值定义很多变量使得工作空间杂乱无章。,工作空间管理,前面我们已经提到,S在运行时保持一个变量搜索路径表,要读取某变量时依次在此路径表中查找,返回找到的第一个;给变量赋值时在搜索路径的第一个位置赋值。但是,在函数内部,搜索路径表第一个位置是局部变量名空间,所以变量赋值是局部赋值,被赋值的变量只在函数运行期间有效。 用ls()函数可以查看当前工作空间保存的变量和函数,用rm()函数可以剔除不想要的对象。如: ls()(或objects()),1 “A“ “Ai“ “b“ “cl“ “cl.f“ “fit1“ “g1“ “marks“

9、 “ns“ 10 “p1“ “rec“ “tmp.x“ “x“ “x1“ “x2“ “x3“ “y“ rm(x, x1, x2, x3) ls() 1 “A“ “Ai“ “b“ “cl“ “cl.f“ “fit1“ “g1“ “marks“ “ns“ 10 “p1“ “rec“ “tmp.x“ “y“ ls()可以指定一个pattern参数,此参数定义一个匹配模式,只返回符合模式的对象名。模式格式是UNIX中grep的格式。比如,ls(pattern=“tmp.“)可以返回所有以“tmp.” 开头的对象名。 rm()可以指定一个名为list的参数给出要删除的对象名,所以rm(list=ls(p

10、attern=“tmp.”) 可以删除所有以“tmp.”开头的对象名。 rm(list=ls() 删除所有对象。,函数定义,S中函数定义的一般格式为“函数名= function(参数表) 表达式”。定义函数可以在命令行进行,例如 hello = function() cat(“Hello, worldn“) ; cat(“n“) ; hello (查看函数具体内容) function () cat(“Hello, worldn“) ;cat(“n“) ; hello() (运行函数) Hello, world,函数体为一个复合表达式,各表达式的之间用换行或分号分开。不带括号调用函数显示函数定义

11、,而不是调用函数。 在命令行输入函数程序很不方便修改,所以我们一般是打开一个其他的编辑程序(如Windows 的记事本),输入以上函数定义,保存文件,比如保存到了C:Rhello.R,我们就可以用 source(“E:/R/hello.R“) 运行文件中的程序。实际上,用source()运行的程序不限于函数定义,任何S程序都可以用这种方式编好再运行,效果与在命令行直接输入是一样的。,对于一个已有定义的函数,可以用fix()函数来修改,如: fix(hello) 将打开一个编辑窗口显示函数的定义,修改后关闭窗口函数就被修改了。fix()调用的编辑程序缺省为记事本,可以用“options(edit

12、or=“编辑程序名“)”来指定自己喜欢的编辑程序。 函数可以带参数,可以返回值,例如: larger = function(x, y) y.is.bigger= (yx); xy.is.bigger = yy.is.bigger; x; 这个函数输入两个向量(相同长度)x和y,然后把x中比y对应元素小的元素替换为y中对应元素,返回x的值。S返回值为函数体的最后一个表达式的值,不需要使用return()函数。不过,也可以使用“return( 对象)”函数从函数体返回调用者。,参数(自变量),函数可以带虚参数(形式自变量)。S函数调用方式很灵活,例如,如下函数: fsub =function(x,

13、 y) x-y 有两个虚参数x和y,我们用它计算100-45,可以调用fsub(100,45),或fsub(x=100,y=45) ,或fsub(y=45, x=100),或fsub(y=45, 100)。即调用时实参与虚参可以按次序结合,也可以直接指定虚参名结合。实参先与指定了名字的虚参结合,没有指定名字的按次序与剩下的虚参结合。 函数在调用时可以不给出所有的实参,这需要在定义时为虚参指定缺省值。例如上面的函数改为: fsub = function(x, y=0) x-y 则调用时除了可以用以上的方式调用外还可以用fsub(100),fsub(x=100)等方式调用,只给出没有缺省值的实参。

14、,即使没有给虚参指定缺省值也可以在调用时省略某个虚参,然后函数体内可以用missing() 函数判断此虚参是否有对应实参,如: trans = function(x, scale) if(!missing(scale) x = scale*x 此函数当给了scale的值时对自变量x乘以此值,否则保持原值。这种用法在其它语言中是极其少见的,S可以实现这一点是因为S的函数调用在用到参数的值时才去计算这个参数的值(称为“懒惰求值”),所以可以在调用时缺少某些参数而不被拒绝。 S函数还可以有一个特殊的“.”虚参,表示所有不能匹配的实参,调用时如果有需要与其它虚参结合的实参必须用“虚参名”的格式引入。例

15、如: f =function(.) for(x in list(.) cat(min(x), n) f(c(5,1,2), c(9, 4, 7) 1 4,作用域,函数的虚参完全是按值传递的,改变虚参的值不能改变对应实参的值。例如: x = list(1, “abc“) x f =function(x) x2 f(x) x,函数体内的变量也是局部的,对函数体内的变量赋值当函数结束运行后变量值就删除了,不影响原来同名变量的值。例如: x = 2 f = function() print(x) ; x= 20 f() 1 2 x 1 2 这个例子中原来有一个变量x值为2,函数中为变量x赋值20,但函

16、数运行完后原来的x值并未变化。但是也要注意,函数中的显示函数调用时局部变量x还没有赋值,显示的是全局变量x 的值。这是S编程比较容易出问题的地方:你用到了一个局部变量的值,你没有意识到这个局部变量还没有赋值,而程序却没有出错,因为这个变量已有全局定义。,程序调试,S-PLUS和R目前还不象其它主流程序设计语言那样具有单步跟踪、设置断点、观察表达式等强劲的调试功能。调试复杂的S程序,可以用一些通用的程序调试方法,另外S也提供了一些调试用的函数。 对任何程序语言,最基本的调试手段当然是在需要的地方显示变量的值。可以用print() 或cat()显示。例如,我们为了调试前面定义的larger()函数,可以显示两个自变量的值及中间变量的值:,larger x); cat(y

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号