R语言编程艺术(3)R语言编程基础

本文对应《R语言编程艺术》

第7章:R语言编程结构;

第9章:面向对象的编程;

第13章:调试

 

=========================================================================

R语言编程结构

控制语句:

循环:

for (n in x) { }
while (condition) { }
repeat { }

  


另外break也可以用在另两种形式的循环语句中。注意repeat没有跳出循环的判断条件,因此使用break(或者类似return())的语句。

除此之外,next语句可以用来跳过本次迭代的剩余部分。具体应用情景,是可以替代循环中的条件嵌套语句,不致代码看起来混乱。

需要注意的是,for结构可以用在任何向量上,无论向量是什么模式,注意灵活运用。

 

对非向量集合的循环:R并不支持直接对非向量集合的循环,但是有一些间接但简单的方式可以做到这点:

使用lapply()。如果循环的每次迭代之间相互独立,就是用lapply(),可以允许以任意顺序执行;

使用get()。这个函数接受一个代表对象名字的字符串参数,然后返回该对象的内容,看起来简单,但是十分有用。

#假设u, v都是两列的矩阵,要分别在这两个矩阵上应用lm函数
for (m in c(“u”, “v”)) {
z <- get(m)
print(lm(z[, 2] ~ z[, 1]))
}

  

if-else结构: 

#注意以下代码
if (r == 4) {x <- 1
} else {x <- 3y <- 4
}

  

虽然if后面只有一条语句,但是它对应的大括号是不能省略的,原因在于R的解释器是根据else前面的右括号判断这是一个if-else结构,如果没有大括号,R将认为这是一个if结构。

#if-else结构的简化
v <- if (cond) expression1 else expression2

  

这是一个简化代码的技巧,因为if-else结构最终会返回的值取决于cond是否为真。如果expression是函数调用语句,可以让代码更为清晰,但是如果语句复杂,就要优先考虑代码是否清晰易懂。

处理向量时,使用向量化的ifelse()函数有可能提高运行速度。

 

 

算术和逻辑运算符及数值:

之前提到,R中只有向量,没有标量,标量可以看作是仅有一个值的向量。但是在逻辑运算时,特别是if语句的条件控制,其逻辑值不能为向量,只能有一个值,也就是可以看作标量。这时,就要区分逻辑与和逻辑或的向量标量运算了。

x && y

标量的逻辑与运算

x || y

标量的逻辑或运算

x & y

向量的逻辑与运算

x | y

向量的逻辑或运算

如果if语句里的控制条件里出现向量并且长度大于1,R的处理方式是将向量的第一个元素作为控制条件返回结果,然后提示warning message

 

 

参数的默认值:

具名实参(named argument):如果不使用默认值,那么在调用函数时必须给出参数的具体名称;

惰性求值(lazy evaluation)原则:除非有需要,否则不会计算一个表达式的值,也就是说具名实参不一定会被使用。

 

 

返回值:

函数的返回值可以是任何R对象。通常为列表形式,但是如果有需要,甚至可以返回另一个函数。

一般来说,如果只在函数结尾返回值,要避免显式地调用return()函数。如果想要将程序表达得更加清晰,在函数中间部分返回值的时候可以显式地调用return()函数。

返回复杂对象:函数的返回值可以是另一个函数。如果函数需要返回多个返回值,可以把它们储存在一个列表或其他容器变量中。

 

 

函数都是对象:

注意到函数是对象,也就是说对于对象的操作对函数也适用。包括创建、编辑,甚至在以函数组成的列表上做循环。

g <- function(h, a, b) h(a, b)
body(g) <- quote(2 * x + 3)
g(3)  # 9

  


首先,function函数创建了一个函数,并赋值给g;然后body函数修改了g的函数体。因为函数主体部分属于”call”类,而这种类是由quote()函数生成。

 

环境和变量作用域的问题:

顶层环境:<environment: R_GlobalEnv>

变量作用域的层次:里层的函数可以使用更加顶层的变量,如果层次之间变量命名发生冲突,优先使用最里层的变量。一般来说,里层对于更加顶层的变量只读不可写。可写的情况将单独讨论。

ls()函数:调用不带参数的ls()可以返回当前的局部变量;使用envir参数可以返回函数调用链中任何一个框架的局部变量名。

函数代码对于其非局部变量一般只读不写,即使重新赋值也是影响它们的备份而不是变量本身。事实上,直到局部变量发生变化前,与其对应的全局变量是共享一个内存地址的。

 

 

R语言中没有指针:

不能直接改变一个函数的参数,只能重新赋值。

其他因为没有指针造成的问题将在下文讨论。

 

 

向上级层次进行写操作:

利用超赋值运算符对非局部变量进行写操作:<<-

注意,超赋值运算符进行写操作的时候,首先逐层向上级环境层次查找,遇到该变量的第一个层次即进行操作,如果没有遇到,将在全局层次上新建变量。

用assign()函数对非局部变量进行写操作:

可以通过设置函数参数指定向上层的哪一层次的变量进行写操作。注意引用变量是使用字符串实现的。

全局变量的使用:一般来说不推荐在函数中写全局变量,但是有时为了简化代码,这么做也是可以的,灵活运用即可。对于大型程序不推荐这样做,因为存在着重写不相关却同名变量的风险。一种折中的方案是,在顶层环境中新建一个封装全局变量的包,再使用assign()和get()函数通过索引到这个包来访问全局变量。

闭包:这里的闭包指一种编程方法,具体做法是,先定义一个可创建局部变量的函数,再创建另一个函数可以访问该变量。这样,后面的一些函数创建的局部变量之间互不影响,各自独立。

 

 

递归:

用于回归和分类的递归分块方法库:rpart

 

 

置换函数:

任何左边不是标识符(意味变量名)的赋值语句都可看作是“置换函数”。当遇到以下形式:

g(u) <- v

  

R语言会尝试用以下方式执行:

u <- “g<-”(u, value = v)

  

直观感受下,就是将值赋值给函数调用的结果。事实上,只要左边不是变量名,就是一个置换语句,比如u[2] <- 8

 

 

写函数代码的工具:

快速载入环境:

 

source(“filename.R”)

  

 编辑函数:

f1 <- edit(f1)
f2 <- edit(f1)

  

 

创建自己的二元运算符:

> “%a2b%” <- function(a, b) return(a + 2 * b)
> 3 %a2b% 5
[1]  13

  

  

匿名函数:

如果函数不是很复杂,可以省去函数定义的过程,在使用function()命令建立函数后直接调用,因为没有具体的函数名,因此称为匿名函数。应用情况取决于具体情况,可以使代码更加易读紧凑。

 

 

=========================================================================

面向对象的编程

  1. 能接触到的R中所有东西(从数字到字符串到矩阵)都是对象
  2. R支持“封装”(encapsulation),即把独立但相关的数据项目打包为一个类的实例。封装可以帮助你跟踪相关的变量,提高清晰度
  3. R类是“多态”(polymorphic)的,这意味着相同的函数使用不同类的对象时可以调用不同的操作。多态可以促进代码可重用性
  4. R允许“继承”,即允许把一个给定的类的性质自动赋予为其下属的更特殊化的类

 

 

S3类:

一个S3类包含一个列表,再附加上一个类名属性和调度(dispatch)的功能。

 

S3泛型函数:即同一个函数可以针对不同的类调用不同的操作。可以通过method()函数找到给定泛型函数的所有实现方法,返回值中,星号标注的是不可见函数(nonvisible function),即不在默认命名空间中的函数,可以通过getAnywhere()函数找到这些函数。另外可以查看一个类能应用的所有泛型函数,代码method(, class = “classname”)

 

编写S3类:“类”属性可以通过attr()或class()函数手动设置。然后可以针对自己编写的类,设定独有的泛型函数,下面是一个例子:

#创建一个名为employee的类的对象
j <- list(name = “Joe”, salary = 55000, union = T)
class(j) <- “employee”
#编写类employee的打印方法
print.employee <- function(wrkr) {cat(wrkr$name, “\n”)cat(“salary”, wrkr$salary, “\n”)cat(“union member”, wrkr$union, “\n”)
}

  


使用继承:继承的思想是在已有类的基础上创建新的类: 

#创建类employee的子类hrlyemployee
k <- list(name = “Kate”, salary = 68000, union = F, hrsthismonth = 2)
class(k) <- c(“hrlyemployee”, “employee”)

  


新类包含了两个字符串,分别代表新类和原有的类,新类继承了原有类的方法,可以使用对应的泛型函数。泛型函数在调度时的工作原理是首先查找两个类名称的第一个,如果没查到,则再去查找第二个类,实现了继承。

 

S4类:

操作

S3类

S4类

定义类

在构造函数的代码中隐式定义

setClass()

创建对象

创建列表,设置类属性

new()

引用成员变量

$

@

实现泛型函数f()

定义f.classname()

setMethod()

声明泛型函数

UseMethod()

setGeneric()

 

编写S4类:

> #定义类employee
> setClass(“employee”,
+   representation(
+     name = “character”,
+     salary = “numeric”,
+     union = “logical”)
+ )[1] “employee”> #创建一个类的实例
> joe <- new(“employee”, name = “Joe”, salary = 55000, union = TRUE)
> joeAn object of class “employee”Slot “name”:[1] “Joe”Slot “salary”:[1] 55000Slot “union”:[1] TRUE> #引用成员变量
> joe@salary[1] 55000> slot(joe, “salary”)[1] 55000> #赋值也可以使用这两种方法
> joe@salary <- 88000
> slot(joe, “salary”) <- 88000

  

S4类的安全性在于,如果给不存在的成员变量赋值,会有报错消息,而S3类将会新建一个成员变量。

> joe@salry <- 48000Error in checkSlotAssignment(object, name, value) :“salry” is not a slot in class “employee”

  

在S4类上实现泛型函数:

#show()函数指在交互模式下,输入变量名直接打印
setMethod(“show”, “employee”,
function(object) {inorout <- ifelse(object@union, “is”, “is not”)cat(object@name, “has a salary of”, object@salary,"and", inorout, "in the union", "\n")
}
)

  

S3类和S4类的对比:

S3具有较强的灵活性,而S4具有很好的安全性。一般来说推荐使用S3使代码更加灵活,而当安全性更加重要时选择S4(比如混合编程的情况下)。

 

 

对象的管理:

ls()函数:列出所有对象;

rm()函数:删除特定对象;

save()函数:保存对象集合,可以用load()载入;

查看对象内部结构的函数:class(), mode(), names(), attributes(), unclass(), str(), edit();

exists()函数:判断对象是否存在。

 

 

=========================================================================

调试

调试的基本原则:

调试的本质:确认原则;

从小处着手;

模块化的、自顶向下的调试风格;

反漏洞。

 

转载于:https://www.cnblogs.com/gyjerry/p/6530099.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用C++流成员函数put输出单个字符

转载&#xff1a;http://c.biancheng.net/cpp/biancheng/view/254.html 在程序中一般用cout和插入运算符“<<”实现输出&#xff0c;cout流在内存中有相应的缓冲区。有时用户还有特殊的输出要求&#xff0c;例如只输出一个字符。ostream类除了提供上面介绍过的用于格式控…

linux 扩充db2表空间,如何扩充db2的表空间、加容器等表空间维护操作

db2 "alter tablespace GJDATA resize (FILE /backup/GJDATA32K45G)"db2 "alter tablespace GJIDX resize (FILE /backup/GJIDX32K45G)"容器路径 db2 list tablespace containers for8容器大小 db2pd -d uibsch -tablespaces降低容器空间 resize 增加容器…

CheckBox控件

前台代码&#xff1a; 1 <asp:CheckBox ID"CheckBox1" runat"server" Text "苹果"/> 2 <asp:CheckBox ID"CheckBox2" runat"server" Text "柠檬"/> 3 <asp:CheckBox ID"CheckBox3" runa…

.NET垃圾回收笔记

名词 垃圾收集目标 ephemeral GC发生在Gen 0 和Gen 1 的垃圾收集 Full GC发生Gen 2 及以上的Gen与LOH的垃圾收集 垃圾收集模式 工作站模式GC直接发生在内存分配的线程&#xff08;也是当前的工作托管线程&#xff09;上 服务器模式每个CPU核都有一个自己独立的GC线程与托管堆 垃…

go.js中的图标(icons)的使用

2019独角兽企业重金招聘Python工程师标准>>> 1、图标库下载&#xff1a; 将icons引入&#xff1a;http://gojs.net/latest/samples/icons.js 2、样式演示 地址&#xff1a;http://gojs.net/latest/samples/icons.html 转载于:https://my.oschina.net/u/2391658/blog…

Pygame - Python游戏编程入门(1)

前言 在上一篇中&#xff0c;我们初步熟悉了pygame的控制流程&#xff0c;但这对于一个游戏而言是远远不够的。所以在这一篇中&#xff0c;我们的任务是添加一架飞机&#xff08;玩家&#xff09;&#xff0c;并且能够控制它进行移动&#xff0c;这样我们就又离目标进了一步了~…

C++字符输入getchar()和字符输出putchar()

转载&#xff1a;http://c.biancheng.net/cpp/biancheng/view/117.html C还保留了C语言中用于输入和输出单个字符的函数&#xff0c;使用很方便。其中最常用的有getchar函数和putchar函数。 putchar函数(字符输出函数) putchar函数的作用是向终端输出一个字符。例如&#xf…

linux实现shell,linux

4.5Mhttp://www.starbase-929.net/media/Calibre%20Library/Ken%20O.%20Bartch/Linux%20Shell%20Scription%20With%20Bash%20(1778)/Linux%20Shell%20Scription%20With%20Bash%20-%20Ken%20O.%20Bartch.pdfstarbase-929.net全网免费4.0Mhttp://www.myaitcampus.net/elibrary/im…

AQS浅析

2019独角兽企业重金招聘Python工程师标准>>> AQS的原理浅析 本文是《Java特种兵》的样章&#xff0c;本书即将由工业出版社出版 AQS的全称为&#xff08;AbstractQueuedSynchronizer&#xff09;&#xff0c;这个类也是在java.util.concurrent.locks下面。这个类似乎…

str045漏洞提权linux,Linux运维知识之CVE-2016-5195 Dirtycow: Linux内核提权漏洞

本文主要向大家介Linux运维知识之CVE-2016-5195 Dirtycow&#xff1a; Linux内核提权漏洞绍了&#xff0c;通过具体的内容向大家展现&#xff0c;希望对大家学习Linux运维知识有所帮助。CVE-2016-5195 Dirtycow&#xff1a; Linux内核提权漏洞以下都是github上找的源码&#xf…

编程如写作

昨晚似乎是个适合写作的夜&#xff0c;不论是自己还是朋友&#xff0c;都比平常更容易被触动。看着微博上朋友们的心路&#xff0c;想写点什么却似乎找不出非常值得大书特书的主题&#xff0c;只是歪坐在电脑旁&#xff0c;喝着咖啡&#xff0c;单曲循环着仓木麻衣的《time aft…

C++中cin、cin.get()、cin.getline()、getline()等函数的用法

转载&#xff1a;http://www.cnblogs.com/flatfoosie/archive/2010/12/22/1914055.html c输入流函数主要以下几个&#xff1a; 1、cin 2、cin.get() 3、cin.getline() 4、getline() 附:cin.ignore();cin.get()//跳过一个字符,例如不想要的回车,空格等字符 1、cin>>…

工作环境总结(1)开发环境搭建

1、安装git 安装文件&#xff1a;Git-2.12.0-64-bit.exe 下载地址&#xff1a;https://github.com/git-for-windows/git/releases/download/v2.12.0.windows.1/Git-2.12.0-64-bit.exe 在git bash中配置&#xff0c;git bash命令行中执行&#xff08;只有使用到egit时使用&…

c语言烟花百度云,C语言实现放烟花的程序

这是一个利用C语言编写放烟花的程序(同时也可以播放音乐)&#xff0c;供大家参考&#xff0c;具体内容如下代码如下#pragma once#include#include //图形界面库头文件#include //计算圆形的轨迹坐标#include#include#include#include#pragma comment(lib,"winmm.lib"…

决定人生的七条公式

1 .积跬步以致千里&#xff0c;积怠惰以致深渊 1.01^365 37.80.99^365 0.032.拖延症 U EV/ID U完成任务的程度 E对成功的信心 V 对任务的愉悦度 I 你的分心程度 D你多久会获得回报3.三天打鱼两天晒网&#xff0c;终将一无所获 1.01^3 x 0.99^2 < 1.01 4.爱因斯坦的成…

strncpy与strcpy的区别与注意事项

strncpy 是 C语言的库函数之一&#xff0c;来自 C语言标准库&#xff0c;定义于 string.h&#xff0c;char *strncpy(char *dest, char *src, int n)&#xff0c;把src所指字符串的前n个字节复制到dest所指的数组中&#xff0c;并返回指向dest的指针。 strcpy只是复制字符串&am…

使用ssh公钥实现免密码登录

ssh 无密码登录要使用公钥与私钥。linux下可以用用ssh-keygen生成公钥/私钥对&#xff0c;下面我以CentOS为例。 有机器A(192.168.1.155)&#xff0c;B(192.168.1.181)。现想A通过ssh免密码登录到B。 首先以root账户登陆为例。 1.在A机下生成公钥/私钥对。 [rootA ~]# ssh-keyg…

15款的视频处理软件免费下载

因为需要购买昂贵的视频处理软件和高性能图形计算机&#xff0c;所以视频处理是一项比较耗费金钱的技术活。正是由于这样&#xff0c;一部分人选择使用性能较好的免费在线编辑软件&#xff0c;无需太多视频处理知识便可在浏览器中剪切和编辑视频。然而&#xff0c;当我们无法连…

液位系统c语言程序,超声波自动测量物体液位系统的设计

超声波自动测量物体液位系统的设计(任务书,毕业论文15000字)摘要本系统以STC89C52单片机为核心&#xff0c;通过硬件电路连接和软件程序的编写实现通用型超声波自动测量物体液位系统的设计。其主要原理是由单片机控制超声波发射电路发射超声波&#xff0c;超声波接收电路接收遇…

android-sdk-windows版本号下载

Android SDK 4.0.3 开发环境配置及执行 近期又装了一次最新版本号的ADK环境 眼下最新版是Android SDK 4.0.3 本文的插图和文本尽管是Android2.2的 步骤都是一样的&#xff0c;假设安装的过程中遇到什么问题&#xff0c;能够留言&#xff0c;我会尽快回复&#xff01; 系统环境的…