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

第四天任务:

完成项目玩扑克牌后1/2,并通过项目学会以下技能:

  1)从一个数据集中抽取个别数据值。

  2)在一个数据集中改变个别数据的取值。

  3)编写逻辑测试程序。

  4)使用R的缺失值符号NA。

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

可以将该项目后1/2分成三个子任务:

1.编写用来发牌和洗牌的函数。

2.改变点数系统以适应不同的扑克游戏。

3.管理扑克牌桌的状态。

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

玩扑克牌应该做扑克牌该做的事,比如洗牌和发牌(从扑克牌堆最上方拿牌)。而对数据进行值的选取,通常值是通过R的记号体系提取:deck[  , ](deck为要操作的数据框,逗号两边为索引参数,左行右列)。R的索引与线性代数的索引一样,都是从1开始的,对R来说有六种索引方式,分别是:

1)正整数索引:deck[i ,j ]或deck[i ,c(1:3)]

R会将值存储为原值的一份副本,可以将副本赋值给对象。如果从数据框中提取两列或两列以上的数据,R会返回新的数据框,只提取一列,R会返回一个向量,如果想让向量变成数据框,需要添加参数drop=FALSE:deck[1:2,1,drop=FALSE]

2)负整数索引

与正整数索引正好相反,R会返回负整数索引对应的元素。

  3)零索引

如果使用零索引,R不会提取任何信息返回一个空对象。

  4)空格索引

使用空格索引提取数据框所有行或者所有列。

  5)名称索引

如果被索引的对象有名称属性,就可以使用名称索引。

deck[1,c(“face”,”suit”,”value”)]

##face   suit  value

##king  spades  13

要想提取数据框的某一列,使用$分隔符分开数据框的名称和要提取的列的名称,并将所有值作为向量返回,因此可以立即将返回结果作为输入交给函数,其操作类似与在列表中使用双中括号返回元素值而不是它的列表结构。

-------------------------对象改值--------------------------

就地改值

R的记号体系可以在R的对象内部改值,即可以将新值覆盖旧值,也可增加新值,这使得可以为数据集添加新变量:

deck$new<-1:52

deck[1,  ]

##face  suit value  new

##kingspades   13    1

在War游戏中,A(ace)的点数是最高的,想要玩War,就要把A的点数从1加到14。如果还没有洗牌,可以知道每13张牌重复一次,因此可以:

deck$value[c(13,26,39,52)]<-14

这些替换操作都是发生在数据集内部,不会产生deck的副本。

逻辑测试

在R中,有七种逻辑运算符,分别是<  ,<= ,>  ,>=  ,== ,!=  ,%in%,其中%in%的用法是a%in%c(a,b,c),代表c(a,b,c)中是否含有a,而且它是唯一一个不一一对比的运算符。所以上面的运算可以改为:

deck$value[deck$face==”ace”]<-14

在Hearts游戏中,除了花色为红桃和黑桃Q的牌,其他点数都是0。

deck$value<-0

deck$value[deck$suit==”hearts”]<-1

deck$value[deck$suit==”spades”&deck$face==”queen”]<-13

在R语言中,布尔运算符有6种,&  ,| ,xor(异或) ,!  ,any  ,all学会使用布尔类型会对数据处理有很大的帮助。

缺失信息

R中的特殊字符NA代表不可用,可用于存储缺失信息。缺失信息不等于0,它代表的是不确定属性,可以将NA看作是可能等于也可能不等于一个数的值。比如1+NA=NA,NA==1##NA。大多数R函数都有一个可选参数na.rm,当na.rm=TRUE时R会在对函数求值时忽略NA。

比如mean(c(NA,1:50),na.rm=TRUE)##25.5

is.na函数用来确定某个值是否是一个缺失值:

vec<-c(1,2,3,NA)

is.na(vec)

##TRUE FALSEFALSE FALSE

这样我们玩Blackjack到时候就可以将ace设置为NA了。

-----------------------------函数设计-------------------------------

两个函数都要求对deck数据框进行直接操作,且发牌函数(deal)要将牌堆上的第一张牌不放回的拿出来,洗牌则是对deck数据集直接打乱顺序。

要想设计好两个函数。就要对R中如何存储,查找和操作对象有所了解。R存储对象时采用了和树形文件管理系统类似的层级系统结构,每一个对象都存储在一个环境当中,每一个环境都与一个父环境相连,一层一层就构成了分层的环境系统。

可以通过devtools包中的parenvs函数查看R中的环境系统。

parenvs(all=TRUE)

R的环境存储在RAM内存中,拥有惟一一个没有父环境的*环境,且不支持自上而下的搜索。R在每一次运性函数的时候都会创建一个新的活动环境,函数是在新环境中运行的。类似与C++中每个函数都有自己的函数空间,在函数内新建的普通变量不能在函数外使用。每次运行一个新的函数R就会创建一个新的环境,最后将求的值返还给就环境中。R就是通过这种方法来确保不会覆已经存在的对象。所以R函数只会调用自己定义的函数。

发牌函数:

deal<-function(){

  card<-deck[1,  ]

  assign(“deck”,deck[-1,  ],envir=globalenv())

  card

}

洗牌函数:

洗牌可以通过随机抽取函数sample来模拟,随机抽取deck中的值,然后将其重新赋值给新的对象即可:

shuffle<-function(){

random<-sample(1:52,size=52)

assign(“deck”,DECK[random,  ],envir=globalenv())

}##该函数在全局变量里输出一个洗好的数据框。

闭包

发牌和洗牌可以统一写入函数setup:

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

新版本与旧版本相比有一个重要的差别,新版本的原环境不再是全局环境,而是R在运行setup函数时所创建的运行环境,这个环境也是R创建DEAL和SHUFFLE的地方。这样处理的方式叫做闭包,setup的运行环境将deal函数和shuffle函数包了起来,两个函数可以直接调用包围式环境的对象,但是其他外部的函数几乎不能做到这一点。这样做使得即使在活跃的全局函数中deck被修改或者删除,也不会影响函数的运行。

这个版本的setup函数不会更新全局环境中的deck对象,只与其所处环境的父环境中的对象合作。

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

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

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

2. 21点(Blackjack)由2到6个人玩,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。