《R语言入门与实践》学习笔记六

时间:2024-03-20 19:40:21

第六天任务:

通过对模拟*项目的改进,学会以下技能:

1)使用S3方法,它是R的面向对象的编程方法。

2)测算R代码的速度。

3)编写快速,向量化的R代码。

…………………………………………………………………………………………

昨天的play函数结果已经看到了,是:

play()

##”0” “0” “DD”

##0

而不是预料中的:

play()

## 0 0 DD

##0

想要完成第二种实现,就要通过R自带的类系统S3系统来解决,它掌管这R如何处理具有不同类的对象。一些函数会首先查询R的S3类,再根据其类属性做出相应的处理。R的S3系统由三个部分组成:属性,泛型函数和方法。

1.属性

查看属性:attributes()。

attr函数可以完成很多关于属性的操作,比如给某个对象添加属性,也可以查询某个对象包含的属性:

《R语言入门与实践》学习笔记六

可以根据以上内容修改play函数,让其更好的输出。

play<-function(){

  symbols<-get_symbols()

  prize<-score(symbols)

  attr(prize,”symbols”)<-symbols

  prize}

现在play函数已经相当接近要求的输出风格了,但是还可以编写slot_display函数美化play函数。

slot_display<-function(prize){

  #提取符号输出结果

  symbols<-attr(prize,”symbols”)

  #将所有符号压缩为一个字符串

  symbols<-paste(symbols,collapse=” ”)

  #用正则表达式将符号与奖金信息组合起来

  #在正则表达式中\n表示另起一个新行

  string<-paste(symbols,prize,sep=”\n$”)

  #在控制台上显示正则表达式的结果,但是去掉其中的引号

  cat(string)

}

通过注释可以大概了解各个函数的使用方法,其输出结果为:

slot_display(one_play)

##B 0 B

## $0

R的泛型函数类似与C++的函数模版,其函数会自动匹配调用对象的类型,比如print()函数就可以输出任何类型的对象。R的方法就是R的使用方法,是根据泛型函数自动分析R的类属性的方法。

泛型函数,方法和基于类的分派方式构成了R的S3系统。通俗来说,当用R中固有函数时,会调用Usemethod函数来识别对象的类属性,根据类属性的不同,选择对应的方法,调整程序的输出格式。

----------------------创建类-----------------------

可以利用S3系统为对象创建一个稳健的类,想要创建一个类,应该执行以下操作:

    1.给类起一个名称。

2.给属于该类的每个对象赋class属性。

3.为属于该类的对象编写常用泛型函数的类方法。

许多R包都是按照相似的方法创建的。

----------------------利用循环计算期望值-----------------------

在计算期望值的时候我们可以分为三步:

1)列出所有可能出现的结果。

2)决定每个结果对应的值。

3)计算每个结果出现的概率。

将第二步结果乘以第三步的结果,加一起就是期望值。

R中的expand.grid函数可以方便快捷的写出n个向量元素的所有组合。

《R语言入门与实践》学习笔记六

我们可以使用类似的方法来解决*问题:

wheel<-c(“DD”,”7”,”BBB”,”BB”,”B”,”C”,”0”)

combos<-expand.grid(wheel,wheel,wheel,stringAsFactors=FALSE)

prob<-c(“DD”=0.03,”7”=0.03,”BBB”=0.06,”BB”=0.1,”B”=0.25,”C”=0.01,”0”=0.52)

combos$prob1<-prob[combos$Var1]

combos$prob2<-prob[combos$Var2]

combos$prob3<-prob[combos$Var3]

combos$prob<-combos$prob1* combos$prob12*combos$prob3

sum(combos$prob)

##1

for循环可以重复运行某段代码一定的次数,R的语法表示如下:

  for(value in that){

this}

在R中for循环不会返回一个输出结果,并且R的佛如循环是针对一个集合来操作的,这是和大多数编程语言不同的地方。

例子: for(value in c(“MY”,”second”,”for”,”loop”)){

        print(value)

       }

##”MY”

##”second”

##”for”

##”loop”

接下来我们更新score函数使其能够处理钻石符号:

score<-function(symbols){

diamonds<-sum(symbols==”DD”)

cherries<-sum(symbols==”C”)

#识别情形

#因为钻石符号是百搭符号,因此只考虑没有钻石的情况

#三个符号相同以及都是杠的情况

slots<-symbols[symbols!=”DD”]

same<-length(unique(slots))==1

bars<-slots %in% c(“B”,”BB”,”BBB”)

#分配奖金值

if(diamond==3){

 prize<-100

}else if(same){

 payouts<-c(“7”=80,”BBB”=40,”BB”=25,”B”=10,”C”=10,”0”=0)

 prize<-unname(payouts[slots[1]])

}else if(all (bars)){

 prize<-5

}else if(cherries>0){

  #如果有一个樱桃

  #则将钻石当作樱桃

 prize<-c(0,2,5)[cherries+diamonds+1]

}else{

 prize<-0}

#根据钻石的数量,把奖金翻倍

prize*2^diamonds

}

我们可以编写for函数来计算每一行的score:

for(1 in1:norw(combos)){

 symbols<-c(combos[i,1],combos[i,2],combos[i,3])

  combos$prize[i]<-score(symbols)

}

然后计算期望值:

sum(combos$prize*combos$prob)

##0.934356

for循环在R中还有两个兄弟,while循环和repeat循环

while(condition){

  code}

其中condition是一个逻辑测试,返回一个逻辑值,每次运行while之前都会运行一遍condition。并且while不会返回任何结果。

repeat更加初级,它会一直重复循环某代码直到你按Esc键终止循环或者遇到break命令。

repeat{code}

system.time函数接受一个R表达式作为输入,运行表达式并显示代码运行时长:system.time(function)

rep函数的作用是重复生成某一值或者向量,并返回一个更长的向量。

long<-rep(c(-1,1),1000000)

-----------------------------注-------------------------------

1.本学习记录来自Garrett Grolemund先生所著《Hands-On Programming with R》(中文名R语言入门与实践)一书。