收藏 分销(赏)

第四章--R编程实践.doc

上传人:二*** 文档编号:4612412 上传时间:2024-10-07 格式:DOC 页数:9 大小:96KB 下载积分:5 金币
下载 相关 举报
第四章--R编程实践.doc_第1页
第1页 / 共9页
本文档共9页,全文阅读请下载到手机保存,查看更方便
资源描述
(word完整版)第四章 R编程实践 第四章 R编程实践 自此,我们已经对R 的功能有个全面的了解。一些数据分析都是在R对话窗口(R Console)中进行的,但对于复杂的数据分析显然是不行方便的。下面将从统计语言和编程角度来说明,我们将会了解一些在R编程实践中采用的简单的概念。 一、 循环和向量化 相比下拉菜单式的程序(R下开发的统计包R Commander),R的一个优势在于它可以把一系列连续的操作简单的程序化.这一点上和所有其他计算机编程语言是一致的,但R有一些特性使得非专业人士也可以很简单的编写程序. 和其他编程语言一样,R有一些和C语言类似的控制结构. (一)控制结构 1。条件语句:条件语句常用于避免除零或负数等数学问题.它有两种形式: 1)if (条件) 表达式1 else 表达式2 2)ifelse(条件,yes,no) 例如: if (x>=0) sqrt(x) else NA ifelse (x>=0,sqrt(x),NA) 2。循环:有三种形式: 1)for (变量 in 向量) 表达式 2)while(条件) 表达式 3)repeat 表达式 例如: 假定我们有一个向量x,对于向量x 中值为b的元素,我们把0赋给另外一个等长向量y的对应元素,否则赋1。我们首先创建一个与向量x等长的向量y: y 〈— numeric(length(x)) for (i in 1:length(x)) if (x[i] == b) y[i] <- 0 else y[i] <- 1 几个指令可以放在一个大括弧里面: for (i in 1:length(x)) { { y[i] 〈- 0 … } x <— rnorm(10,—5,0.1) y <- rnorm(10,5,2) X <- cbind(x,y) # 矩阵X的列名保持”x” 和”y" for (i in 1:5/2) z[i] 〈— x[i] + y[i] 另外一种可能的情况是当条件为真的时候一条指令才执行: while (myfun > minimum) { … } count〈-0 while (count<10){ print(count) count=count+1 } #如果设置不正确while循环可以能导致无限循环,要小心 #computeEstimate() x0〈-1 tol<—1e-5 repeat{ x1<—rnorm(1,1,2) if (abs(x1—x0)〈tol){ break }else{ x0〈-x1 } } #next,return for(i in 1:100){ if(i〈=20){ ##skip next } #do somthing here } 3.分支控制语句 switch(statement,list) switch(2,’banana’,’apple’,'other’) num〈—10 mode<-num%%3 #模3 cat('mode is',switch(mode+1,0,1,2),'\n’) 例子见“客观赋权法。R". (二)向量化 但是,由于R的一些特性,在很多情况下循环和控制结构可以避免:向量化.向量化使得循环暗含在表达式中, 前面的例子中已经多次采用了.比如,两个向量之和: > z 〈- x + y 这种加和可以通过循环结构来实现, 就像很多编程语言采用的策略一样: > z <— numeric(length(x)) 〉 for (i in 1:length(z)) z[i] <- x[i] + y[i] 在这个例子中,由于要用到向量的下标系统,有必要预先创建一个向量z. 显然,这种显式的循环仅仅用于向量x和y等长的情况:如果不是这样程序代码需要改变,而第一种表达方式在任何情况下都成立(如果对R的向量循环使用方式不了解的话,x和y不等长时要小心一点)。 条件语句(if… else) 可以用逻辑索引向量代替;同样上面的例子: 〉 y[x== b] 〈— 0 〉 y[x!= b] <— 1 除了让代码更简洁,向量化的表达式在计算上效率更高,特别是大数据量的数据集. (三)运用apply等函数 有多个’apply' 形式的函数用于避免使用代码的显式循环结构。apply 作用于矩阵的行或者/和列,它的语法规则是apply(X,MARGIN,FUN,…),其中X是一个矩阵,MARGIN 表明是对行(1)还是列(2),或者二者(c(1,2))进行操作,FUN 是一个函数(或操作符,但是这种情况下操作符要在一个括弧里面指定),…是函数FUN可能的参数。一个简单的例子如下。 > x <- rnorm(10,-5,0.1) > y 〈- rnorm(10,5,2) > X <- cbind(x,y) # 矩阵X的列名保持”x" 和"y” 〉 apply(X,2,mean) lapply() 可以用于一个列表对象:它的语法类似apply 并且返回一个列表对象。 > forms <- list(y~x,y ~ poly(x,2)) 〉 lapply(forms,lm) sapply() 是函数lapply() 一个更为灵活的变种,它可以接受向量或者矩阵作为主要参数,并且返回形式更为友好的结果,常常是表格方式。还有sweep()、tapply()函数等。 例如: >attach(mtcars) >tapply(mpg,cy1,mean) 〉col.mean=apply(mtcars,2,mean) 〉sweep(mtcars,2,col.mean,—) 表示从数据框mtcars中按列计算col.mean,并从mtcars中减去。 二、 用R写程序 一般情况下,一个R程序以ASCII 格式保存,扩展名为`.R’。如果一个工作要重复好多次,用R程序是一个不错的选择。在我们的第一个例子中,我们想对三个不同种属的鸟绘制一样的图,而且数据在三个不同的文件中.我们将一步一步的演示看R用不同的方式去完成这个简单的问题. 首先,我们凭直觉连续键入一系列命令,而且预先分割图形设备。 layout(matrix(1:3,3,1)) #分割图形界面 data 〈— read。table(”Swal.dat") #读入数据 plot(data$V1,data$V2,type="l") title(”swallow") #增加标题 data <- read。table("Wren。dat”) plot(data$V1,data$V2,type=”l”) title("wren”) data 〈- read。table(”Dunn。dat") plot(data$V1,data$V2,type="l”) title("dunnock”) 字符`#' 用于在程序中添加注释行:R会自动跳过注释行。 第一个程序的问题是在我们加入另外一个物种数据时,它过长。此外,一些命令多次执行, 因此它们可以放在一起,在执行的时候仅仅修改一些参数。这里的策略是把参数放到一个字符型的向量中去,然后用下标去访问这些不同的值。 layout(matrix(1:3,3,1)) # 分割图形界面 species <— c(”swallow”,"wren","dunnock”) file <— c(”Swal。dat","Wren。dat”,"Dunn。dat") for(i in 1:length(species)) { data 〈- read。table(file[i]) # 读入数据 plot(data$V1,data$V2,type=”l") title(species[i]) # 增加标题 } 注意代码read。table()里面的参数file[i] 上面没有双引号, 因为这个参数是字符型。 现在的代码比较紧凑.它比较容易加入新的物种, 因为设置物种名字和数据文件的向量都程序的前端. 如果扩展名为`。dat’的数据文件在R的工作目录下面,程序可以正常运行,否则用户要设置工作目录,或者设置绝对路径(例如:file <- ”/home/paradis/data/Swal。dat")。如果程序保存在文件Mybirds.R 中,可以通过键入如下命令执行: 〉 source("Mybirds.R") 和所有以文件作为输入对象的函数一样,如果该文件不在当前工作目录下面,用户需要提供该文件的绝对路径。 三、 编写你自己的函数 (一)编写自己的函数 1.函数的基本操作 大多数R的工作是通过函数来实现,而且这些函数的输入参数都放在一个括弧里面.用户可以编写他们自己的函数,并且这些函数和R里面的其他函数有一样的特性。 stdev=function(x) { #计算标准差 sqrt(var(x)) } stdev z=1:3 stdev(z) 函数的返回值可以是任何R对象,甚至可以是另一个函数。可以通过显式地调用return(),把一个值返回给主调函数。如果不用这条语句,默认会将最后执行的语句的值作为返回值。例如: oddcount<—function(x){ k<—0#k的初始值 for(n in x){ if(n%%2==1)k=k+1#%%是模 } return(k) } 这个函数返回参数x中奇数的个数。 如果函数的输出包括多个变量,可以把他们集中在一个列表中,以列表为参数调用函数,让这个函数返回列表. 创建函数之后可以通过函数formals()和body()来查看其参数。 formals(oddcount) body(oddcount) 可以使用page()一个函数的代码,确定它的功能和用法. page(abline) 函数内变量的赋值只在函数内有效。编写自己的函数可以让你有效的,灵活的与合理的使用R.我们再次使用前面读数据并且画图的例子。如果我们想在其他情况下进行这样的操作,写一个函数是一个不错的想法: myfun <— function(S,F) { data <— read。table(F) plot(data$V1,data$V2,type="l”) title(S) } 执行时,这个函数必须载入内存。当然,这有多种方式实现。和所有其他命令一样,函数的各行可以直接通过键盘键入,或者从一个文本编辑器里面拷贝粘贴。如果函数保存在一个文本文件中, 可以命令source() 载入。如果用户期望一些函数在R启动时就被载入,可以把它们保存在工作目录下面的文件.RData中.另外一种方式是,配置文件`.Rpro¯le'或`Rpro¯le’ (详见?Startup for details)。最后,还可以创建一个包,但是这里不想多讨论. 一旦函数载入后,我们就可以键入一条命令以读入数据和画出我们想要的图,如myfun(”swallow","Swal.dat”)。因此,现在我们的程序有第三个实现的版本了: layout(matrix(1:3,3,1)) myfun("swallow","Swal。dat") myfun("wren”,"Wrenn。dat") myfun(”dunnock”,"Dunn.dat”) 我们还可以用sapply() 实现程序的第四个版本: layout(matrix(1:3,3,1)) species <- c("swallow","wren","dunnock”) file <— c("Swal.dat”,"Wren.dat”,”Dunn。dat") sapply(species,myfun,file) 2.环境与变量的作用域 在R里面,没有必要在一个函数里面进行变量声明。当一个函数执行时,R用一种称为词汇作用域(lexical scoping)的规则决定一个对象的作用域相对一个函数是局部还是全局。为了理解这种机制,我们可以认真研究一下下面的一个简单函数: 〉 foo <— function() print(x) > x <— 1 > foo() [1] 1 x 不是为了在函数foo()里面创建对象,因此R 将会在封装环境中搜索是否有个名为x 的对象, 和打印它的值(否则一条错误信息将会显示,执行中断)。 如果x是我们定义的函数中一个对象的名字,全局环境中变量x 值将会被采用。 > x <— 1 〉 foo2 〈— function() { x <— 2;print(x) } 〉 foo2() [1] 2 > x [1] 1 此时,print() 使用在它所在的环境中定义的x,即环境foo2 中的x。 前面提及的”封装"是关键所在。在前面两个演示函数中,有两个环境:全局环境和函数foo 或foo2的局部环境。如果有三个或者更多的嵌套环境,对象搜索将逐层搜索直到全局环境。 rm(list=ls()) ls() ls.str()可以获得更多信息。 有两种方式指定一个函数的参数:通过它们的定义时的位置或者名字(又称为标签参数)。 例如,假定一个函数有三个参数: foo 〈- function(arg1,arg2,arg3) {…} foo() 在执行时可以不用名字arg1,…,如果相应的参数对象放在相应的位置上,如:foo(x,y,z)。但是,如果使用了参数的名字,位置信息将会失效,如foo(arg3 = z,arg2 = y,arg1 = x)。R函数的另外一个特性是函数可能采用定义时的默认设置。例如: foo <— function(arg1,arg2 = 5,arg3 = FALSE) {…} 命令foo(x),foo(x,5,FALSE) 和foo(x,arg3 = FALSE) 将会得到一样的结果.使用一个函数的默认设置非常有用,特别在使用标签参数的时候,如foo(x,arg3 = TRUE) 仅仅改变一个默认设置. 环境层次中,某一层次的代码对它上级层次中所有变量至少有读的权限。但是,通过标准的运算符〈—直接对上级层次的变量进行写操作是不可行的。 #观察w的值是否有变化 w<—12 f<—function(y){ d<—8 w<—w+1 y<—y-2 cat("w=",w,”\n”) h〈-function(){ return(d*(w+y)) } return(h()) } f(2) cat(”w=”,w,"\n") 如果你希望对一个全局变量,或者更一般情况下,对当前层次的上级层次中任意变量进行写操作,可以在当前层次使用超赋值运算符〈〈-,或者函数assign(). (二)函数的调用 函数也是对象,也可以给它们赋值,把它们用作其他函数的参数,如下所示: #函数的调用 f1<-function(a,b) return(a+b) f2〈-function(a,b) return(a—b) f<—f1 f(3,2) f<—f2 f(3,2) g<-function(h,a,b) h(a,b) g(f1,3,2) g(f2,3,2) #在同一幅画上绘制若干个函数的图形 g1<—function(x) return(5*sin(x)+5) g2<-function(x) return(sqrt(x^2+1)) g3〈-function(x) return(2*x-1) plot(c(0,6.5),c(—5,15))#准备绘图,确定x和y的区域 for(f in c(g1,g2,g3))plot(f,0,6.5,add=T)#在原有的图形上绘图 (三)函数编辑 R提供了一个edit函数,让使用者可以在一个特定的窗口中更改自己的函数;fix使用预设的编辑器。 fix(stdev) edit(file="for。r") 我们来看另外一个例子.尽管这个例子不是纯的统计学例子,但是它很好地展示了R 语言的灵活性。假定我们想研究一个非线性模型的行为:这个模型(Ricker 模型)的定义如下: 这个模型广泛地用于种群动态变化(population dynamics)的研究里面,特别是鱼类的种群变化。 我们想用一个函数去模拟这个模型关于增长率r和初始群体大小N0的变化情况(承载能力K 常常设定为1且以这个值作为默认值)的影响;结果将以种群大小相对时间的图表示。我们还将设定一个可选项允许用户只显示最后若干步中种群大小(默认所有结果都会被绘制出来)。下面的函数就是做Ricker模型的数值模拟的。 ricker 〈- function(nzero,r,K=1,time=100,from=0,to=time) { N 〈- numeric(time+1) N[1] 〈— nzero for (i in 1:time) N[i+1] <— N[i]*exp(r*(1 — N[i]/K)) Time 〈- 0:time plot(Time,N,type=”l",xlim=c(from,to)) } 你可以试一试下面的代码: 〉 layout(matrix(1:3,3,1)) > ricker(0。01,0.1);title("r = 0。1”) 〉 ricker(0.05,0.2);title("r = 0。2") 〉 ricker(0。1,0。3);title(”r = 0.3”) 四、 防错、除错与调试 1。防错与除错 R具备在函数中加入防错功能的应用函数:stop()和warning()。stop()会传回错误信息并终止执行函数;warning()则在传回错误讯息的同时继续执行函数. stdev=function(x) { #计算标准差 if (!is。vector(x)) stop("向量才能计算标准差”) else sqrt(var(x)) } z=3 z=as。matrix(z) stdev(z) #利用输出cat语句进行确认 g=function(x,y){x^2-y+1} z〈—0 x〈—y^2+3*g(z,2) cat("x=”,x,"\n") #利用print语句进行调试 x<—y^2+3*g(z,2) cat(”x=”,x,"\n”) w〈—28 q<—12 if(w+q>0){ u<-1 print(”the ’if' was done”) }else{ v〈-10 print("the ’else' was done”) } 2。调试 R的核心调试工具由浏览器(browser)构成,它可以让你逐行运行代码,并在运行过程中检查。可以用有内置除错函数debug()或browser()函数来打开这一浏览器。 R的调试工具是针对单个函数的,如果你认为函数f()中有漏洞,就可以调用debug(f)来设置函数的调试状态。调用undebug(f)将取消函数的调试状态。 debug(stdev) stdev(z) 如果你只想对f()进行一次调试会话,可以使用debugonce(f)函数,会在f()第一次执行时对其设置调试状态。 你果你认为漏洞离函数的开始部分较远,可以在函数的某一行加入browser()语句,那么浏览器只在程序执行到这一行时被打开。 #设置断点 f=function(x){x^3-2*x-1} root=function(x,y){ if(f(x)*f(y)==0)browser() x1〈—x;x2〈-y if (f(x1)*f(x2)〉0) stop("区间端点的f()值之正负号不相反”) else{ if(f(x)>0) {x1〈-y;x2〈—x} } tol〈—1e-5 repeat{ x0〈—(x1+x2)/2 if (f(x0)〉0){ x2<-x0 }else{ x1〈-x0 } if (abs(x1-x2)〈tol){ return(x1) break } } } plot(f,xlim=c(-1.5,2)) abline(h=0) root(-1,1) 进入调试浏览器时,命令提示符将从〉为变更为Browser[d](d表示函数调用链的深度)。在命令提示符之后你可以输入以下命令: n(代表next):执行下一行然后暂停,直接键入Enter也一样. c(代表continue):与n类似,但是如果当前在某个循环中,将会执行剩余的循环退出循环才会暂停。如果你不在某个循环中,那么下一次暂停前函数的剩余部分将被执行。 任意的R命令:在浏览器中,你依然处在R的交互模式,因此可以任意查看变量的取值. where:会输出一份栈跟踪路径,即显示到达当前位置的过程中函数的调用序列。 Q:该命令将会退出浏览器,返回R的交互模式. setBreakpoint(“f.R”,10) 思考与练习题 4.1运行如下程序,观察其结果: >total=0 〉for (i in c(1,2,4,5,9)) >total=total+i >total 4.2编写一个用二分法求非线性方程根的函数,并求方程: 在区间[1,2]内的根,精度要求e=10—5。 4.3根据“客观赋权法。R"中的程序,学习switch分支控制语句的用法(查找帮助文件). 4。4。根据数据集hw1_data编写程序,运用apply、tapply等函数回答下面问题: (1)数据集臭氧值(Ozone)、太阳光(Solar。R)、风力(Wind)和温度(Temp)的平均值各是多少? (2)按月(Month)平均的 “Temp"值是多少? 4.5试编写函数is.sym()检查矩阵是否为方阵,然后检查矩阵是否对称,输出True、False或适当的错误信息。 4.6试编写函数oddsevens(),返回一个参数x中奇数和偶数的个数。 4.7试编写函数findruns()寻找由0、1构成的向量x连续出现长度为k的1的游程个数.例如对于向量(1,0,0,1,1,1,0,1,1),从它的第4个元素开始有长度为3的游程,而长度为2的游程分别开始于第4、5、8的位置。 4。8试编写函数pread()进行天气预测(1代表有雨、0代表没有雨).根据天气的历史数据x选择最近k天的天气记录预测下一天的天气;对历史数据进行训练(随机生成),比较不同的k,选择误差最小的k用于未来的预测. 9
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服