收藏 分享(赏)

第四讲-程序设计.ppt

上传人:精品资料 文档编号:9720565 上传时间:2019-08-28 格式:PPT 页数:36 大小:613.50KB
下载 相关 举报
第四讲-程序设计.ppt_第1页
第1页 / 共36页
第四讲-程序设计.ppt_第2页
第2页 / 共36页
第四讲-程序设计.ppt_第3页
第3页 / 共36页
第四讲-程序设计.ppt_第4页
第4页 / 共36页
第四讲-程序设计.ppt_第5页
第5页 / 共36页
点击查看更多>>
资源描述

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

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

3、符号)表示“或”,它也是短路运算符,当第一个条件为真时就不再计算第二个条件。,在用R编程序时一定要时刻牢记R是一个向量语言,几乎所有操作都是对向量进行的。而R中的if语句却是一个少见的例外,它的判断条件是标量的真值或假值。比如,我们要定义一个分段函数f(x),当x为正时返回1,否则返回0,马上可以想到用if语句实现如下:if(x0) 1 else 0 当x是标量时这个定义是有效的,但是当自变量x是一个向量时,比较的结果也是一个向量,这时条件无法使用。所以,这个分段函数应该这样编程:y= numeric(length(x) yx0 yx=0 - 0 # 这句可以省略,对于条件语句是向量形式,R提

4、供了ifelse()函数,它的使用格式为ifelse(condition, a, b) 它表示,当conditioni成立的时候,对应的取值为ai,否则取值为bi。最终返回一个和参数向量同长的向量 x a ifelse(x=60, a, b)1 “fail“ “pass“ “pass“ “pass“ a b ifelse(x=60, a, b)1 “b1“ “a2“ “a3“ “a4“,若a,b和x不是等长的,则较短的循环使用,有多个if语句时else与最近的一个配对。可以使用if . else if . else if . else .的多重判断结构表示多分支。多分支也可以使用switch(

5、)函数。 x=0; if (x0) value value1 ZERO“,switch语句,switch是多分支语句,其用法为: switch (statement, list); statement是一个表达式,list是列表,也可以用有名定义。根据表达式与list的关系返回一个值。如果表达式返回值属于1:length(list)中的一个,则返回list中相应位置的值,否则返回NULL。 a a x a a - switch (4, 2+2, mean(1:10), rnorm(4); a 1 NULL,当list是有名定义时,statement等于变量名时,返回该变量名所对应的值,否则返回

6、NULL x a x a - switch (x, fruit=“apple“, drink=“coffee“, vegetable=“broccoli“); a1 NULL,循环结构(for/while/repeat) for语句,循环结构中常用的是for循环,是对一个向量或列表的逐次处理,格式为 for( name in values) expression 如:求1到100的和 sum-0;for(i in 1:100)sum-sum+i; i-i+1 sum;1 5050,当然,如果只是要求各元素的和,只要调用sum(x)即可。所以,编写程序要精简,应尽量避免使用显式循环。 我们再举一

7、个例子。比如,我们要计算同生日的概率。假设一共有365个生日(只考虑月、日),而且各生日的概率是相等的(这里忽略了闰年的情况以及可能存在的出生日期分布的不均匀)。设一个班有n个人,当n大于365时至少两个人生日相同是必然事件。当n小于等于365时,我们可以计算P至少有两人同生日= 1 - Pn个人生日彼此不同,这时,n个人的生日可取值数为365n ,而n个人彼此不同的可能数为365中取n个的排列数,彼此不同的概率为P3n65 。因此,为了计算n1,2,.,365的情况下的同生日概率,可以用如下循环实现:, x = numeric(365) for(i in 1:365) xi= 1 for(j

8、 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!,这会 超出数值表示范围。,我们有时候需要在某个判定条件成立的时候开始循环,一旦条件不成立,就终止循环,这时可以用while循环语句。 while循环是在开始处判断循环条件的,用法为:while (condition) expression表示在condition成立的时候,执行expression。 例:一段二分法解方程的程序。 eps while(b-aeps) c 0) b

9、 - c else a - c,while语句,例:1000以内Fibonacci数列的生成 f while(fi+fi+1 f1 1 1 2 3 5 8 13 21 34 55 89 14413 233 377 610 987,repeat语句是while不一样,把条件加在末尾,依赖break命令跳出循环,基本用法是:repeat expressions;if (condition) break表示一直重复表达式的计算,知道condition成立的时候,跳出循环。,repeat语句,例(续):用repeat语句生成1000以内Fibonacci数列 f repeat fi+2 =1000)

10、break; f1 1 1 2 3 5 8 13 21 34 55 89 14413 233 377 610 987,编写自己的函数,R允许用户创建自己的函数。事实上,R本身提供的绝大多数函数如sum(), plot()等,是编写人员写在R中的,与用户自己创建的函数没有本质上的区别。 R中函数定义的一般格式为function.name hello = function() cat(“Hello, worldn“) ;, hello #查看函数具体内容function () cat(“Hello, worldn“); hello() #运行函数Hello, world 函数体为一个复合表达式,各

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

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

13、可以调用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乘以此值,否则保持原值。这种用法在其它语言中是极其少见的,R可以实现这一点是因为R的函数调用在用到参数的值时才去计算这个参数的值(称为“懒惰求值”),所以可以在调用时缺少某些参数而不被拒绝。 R函数还可以有一个特殊的“.”虚参,表示所有不能匹配的实参,调用时如果有需要与其它虚参结合的实参必须用“虚参名”的格式引入。例如: fmin fmin(c(5,1,2), c(9, 4, 7

15、)1 1 4,作用域,函数的虚参完全是按值传递的,改变虚参的值不能改变对应实参的值。例如: x = c(1, “abc“) x 1 “1“ “abc“ f =function(x) x2 f(x) 1 “1“ “!“x 1 “1“ “abc“ 这个例子说明了函数体内部的变量是局部的,赋值只针对函数体的变量,一旦函数运行结束以后,不改变全局变量的值。,函数体内的变量也是局部的,对函数体内的变量赋值当函数结束运行后变量值就删除了,不影响原来同名变量的值。例如: x f f() 1 2 x 1 2 这个例子中原来有一个变量x值为2,函数中为变量x赋值20,但函数运行完后原来的x值并未变化。但是也要注

16、意,函数中的显示函数调用时局部变量x还没有赋值,显示的是全局变量x 的值。这是R编程比较容易出问题的地方:你用到了一个局部变量的值,你没有意识到这个局部变量还没有赋值,而程序却没有出错,因为这个变量已有全局定义。,R程序设计注意要点,对于复杂一些的计算问题我们应该编写成函数。这样做的好处是 编写一次可以重复使用,并且可以很容易地修改 函数内的变量名是局部的,运行函数不会使函数内的局部变量被保存到当前的工作空间,可以避免在交互状态下直接赋值定义很多变量使得工作空间杂乱无章。,编写函数是要注意: 可读性(readability). 可理解性(understandability).具体要做到: 采用

17、结构化、模块化编程; 增加必要的注释; 使用意义明确的名字作为变量名,切忌用人名或者宠物名; 行前缩进,使程序有层次感。,工作空间管理,R在运行时保持一个变量搜索路径表,要读取某变量时依次在此路径表中查找,返回找到的第一个;给变量赋值时在搜索路径的第一个位置赋值。但是,在函数内部,搜索路径表第一个位置是局部变量名空间,所以变量赋值是局部赋值,被赋值的变量只在函数运行期间有效。 用ls()函数可以查看当前工作空间保存的变量和函数,用rm()函数可以剔除不想要的对象。如: ls()(或objects()),1 “A“ “Ai“ “b“ “cl“ “cl.f“ “fit1“ “g1“ “marks“

18、 “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

19、attern=“tmp.”) 可以删除所有以“tmp.”开头的对象名。 rm(list=ls() 删除所有对象。,程序设计举例,设计R程序是很容易的,在初学时我们只要使用我们从一般程序设计中学来的知识并充分利用R中现成的各种算法及绘图函数就可以了。但是,如果要用R编制计算量较大的程序,或者程序需要发表,就需要注意R程序设计的一些技巧。 用R语言开发算法,最重要的一点是要记住R是一个向量语言,计算应该尽量通过向量、矩阵运算来进行,或者使用R提供的现成的函数,避免使用显式循环。显式循环会大大降低R的运算速度,因为R是解释执行的。,n=1:10; x=sin(n*pi/10); cat(x=,x)

20、1 x= 0.309017 0.5877853 0.809017 0.9510565 1 0.9510565 0.809017 0.5877853 0.309017 1.224606e-16 fsin - function(x)sin - 0;for ( i in 1:length(x) sini - sin(xi*pi/10);return(sin); y - 1:10; fsin(y);1 3.090170e-01 5.877853e-01 8.090170e-01 9.510565e-01 1.000000e+006 9.510565e-01 8.090170e-01 5.877853e

21、-01 3.090170e-01 1.224606e-16,例 对n=1,2,10,求xn= 的值,Money.R money=10000 years=0 while (money20000)years=years+1; money=money*(1+2.52/100) ,例 设银行年利率为2.52%。将10000元钱存入银行,问至少多长时间会连本带利翻一番?, source(Money.R); years; money; 1 28 1 20074.31, fun1=xx12+1; yx fun(c(1,2,3) 1 fun= 2 5 10,例,存款函数deposit() deposit -

22、function(amount, total) if(amount = 0)stop (“Deposits must be positive!n“)total - total + amount; cat (amount, “deposited. Your balance is“, total, “nn“); ,例 考虑一个简单的银行存取款系统,取款函数withdraw() withdraw total)stop (“Sorry, you dont have that much money!n“)total - total - amount; cat (amount, “withdrawn. Y

23、our balance is“, total, “nn“); ,存取款平衡函数blance()balance - function(total) total - total; cat (“Your balance is“, total, “nn“); ,开户函数open.account() 上面的几个函数可以合作一起,编写成一个开户函数,只要知道开户的总额,就可以根据每次存取款额,直接给出余额(见下页), total client client $ deposit (20); client $ withdraw (200); client $ withdraw (40); client $ balance ( );,实验练习:对以下问题,编写R文件:,(1) 编程求出矩阵最大值及其所在的位置. 要求: 编写通用函数,然后对不同的矩阵调用输出相应的结果,比如 A=matrix(floor(rnorm(100,0,4),4,25) (2)有一函数 ,写一程序,输入自变量的值,输出函数值.,不超过X的最大整数,(3) 有缺失数据矩阵的插补。对缺失矩阵每一列的缺失值用该列所有观测到数据的平均值代替,得到新的无缺失值矩阵。 要求同(1), 例如 A=matrix(floor(rnorm(100,0,4),4,25) A2,5=NA; A4,8=NA; A3,15=NA,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报