【用R玩老虎机】——《R语言入门与实践》第7到10章(程序、S3、循环、代码提速)

 个人简介

第七章 程序

在function的花括号中使用print()函数可以显示函数内部生成的相关信息。

7.1 策略

策略可以理解为流程图里选择串联还是并联。完成一个任务的简单的策略就是把它分成几个小的任务。

  1. 讲复杂的任务分解为一些简单的子任务
  2. 使用实例
  3. 用通俗的语言描述解决方案,然后将其转换为R代码

7.1.1有序步骤sequential step :串联

7.1.2同类情况parallel case:并联 

串联加并联 -> 完整的程序

7.2 if语句

if (this) {

        that

}

7.3else语句

if (this) {
    Plan A
} else if (that) {
    Plan B
} else {
    Plan C
}

trunc 函数是提取整数部分的函数。a - trunc(a) 是返回数值a小数部分的一种十分便捷的方法。 

 如果能够一次专注于一个问题,那么最后其实可以节省很多时间,并免去很多令人头疼的麻烦。比如这里面,我先写出策略,然后用if else 写出框架,用代码注释,然后一块一块往里填充。

#测试三个值是否相同
symbols[1] == symbols[2] & symbols[2] == symbols[3]
## TRUE

#更好的方案
length(unique(symbols)) == 1
#unique 返回一个向量中的所有非重复值。如果symbols全相同,unique返回一
#个长度为1的向量

symbols[1] == symbols[2] && symbols[2] == symbols[3]
## TRUE

# && 和 || 的效果与单个的类似,区别是前者如果第一个测试结果明确,直接
#返回结果。不过他们不是向量化的,也就是意味着它们的两侧只能是单个逻辑测试

7.4查找表

在R中,许多极简的解决方案经常会用到取子集 ( subsetting ) 的方法。

menu <- c("A" = 1, "B" = 2, "C" =3, "D" =4, "E" = 5)
menu
## A    B    C    D    E
## 1    2    3    4    5

menu["A"]
## A
## 1

unname(menu["A"])
## 1

如果if树的分支运行不同代码,就不该被查找表取代。 

same <- length(unique(x)) == 1
bars <- x %in% c("ha", "haha", "hahaha")

if (same) {
    menu <- c("A" = 1, "B" = 2, "C" = 3, "D" = 4)
    prize <- unname(menu(x[1]))
} else if (all(bars)) {
    prize <- 10
} else {
    nuts <- sum(symbols == "wu")
    prize <- c(0,2,5)[nuts + 1]
}

diamonds <- sum(symbols == "dd")
prize * 2 ^ diamonds

7.5代码注释

用#给代码加注释

RStudio Code 菜单里的Extract Function 提取函数。

7.6小结

第八章 S3

8.1 S3系统

S3指的是R自带的类系统。这个系统掌管着R如何处理具有不同类的对象。

R的S3系统有三个部分:属性、泛型函数、方法。

属性不会影响对象的实际取值,但是作为该对象的某种类型的元数据,可以被R用于控制和管理这个对象。

8.2 属性

attribute()查看函数属性。属性不影响对象的实际取值,但是作为该对象的某种类型的元数据,可以被R用于控制和管理某种对象。

attr()函数接受两个参数:一个R对象和某种属性的名称(以字符串的形式)。要赋予R对象具有指定名称的某个属性,需要将某个值保存到attr 的输出结果。

attr(one_play, "symbols") <- c("B", "0", "B")

如果不加后面的c,attr可以查找某个属性的取值。

structure函数可以将运算和设置属性值合并为一步来完成。structure创建的是带一组属性的R对象。该函数的第一个参数应该是一个R对象或者对象的取值,剩下的参数是你想要添加给这个对象的属性。属性的名称可以任意设置。

structure(score(symbols), symbols = symbols)

paste

paste 中的collapse参数如果被赋值,便会将一个字符型向量中的元素压缩成单个字符串。用collapse参数的值作为分隔字符串向量中不同元素的分隔符。

paste 可以放两个对象,用sep参数里的值将新字符中的不同元素分割开来。正则表达式中\n是换行的意思。但是paste输出时还是\n,没有换行

cat 函数和print相似,然而cat不会在输出结果的两侧添加双引号。它还会将所有的\n替换为一个新行或换行符。

8.3 泛型函数

print是一个泛型函数。print函数总会在控制台窗口中显示其参数的内容。

print函数会查找某个对象的class,再根据class的不同,使用一个if树分配合理的输出显示方式。

8.4 方法

print函数调用了一个特别的函数UseMethod(使用方法),后者会检查你提供给print函数的第一个args的class,再用处理这种class的函数处理数据。

将某个泛型函数作为输入对象运行methods函数,可以看到该泛型函数所支持的方法。

##这样一个由泛型函数、方法和基于类的分派方式所构成的系统就是R的S3系统。之所以叫做 S3是由于它起源于S的第三个版本,S语言是S-PLUS和R语言的前身。

每个S3方法的名称都包含两个部分。前一部分指明该方法对应的函数,后一部分指明类属性。

<function.class>

print.slots <- funtion(x, ...) {
    slot_display(x)
}

game <- function( ) {
    symbols <- get_symbols()
    structure(score(symbols), symbols = symbols, class = "slots")
}

8.5 类

可以利用R的S3系统为对象新建一个稳健的类 ( class )。

8.6 小结

S3系统为在R中创建基于对象的行为提供了一条捷径。它就是R的面向对象编程(Object-Oriented Programming, OOP) 系统。这个系统是通过泛型函数来实现其功能的。这些泛型函数会检查其输入对象的类属性,并有针对性地生成基于类属性的输出结果。

第九章 循环

9.1 期望值

9.2 expand.grid

expand.grid(A,B,C) 输出ABC中的所有对象的所有组合,维度由expand.grid接受的对象个数决定。

9.3 for循环

for (value in that) {
    this
}

for (AnythingULike in c("A", "B", "C") {
    print(AnythingULike)
}
## "A"
## "B"
## "C"

循环语句会在活动中运行代码,所以它创建的对象将覆盖当前环境中已经存在的对象。 

for循环没有输出功能。What happens here, stays here.

要想保存for循环的输出结果,可以在运行for之前先创建一个空的向量或列表,然后用for填满。

for循环并不是主要用于运行代码,而是用于将代码的运行结果填入向量和列表。

9.4 while循环

while(condition) {
    code
}

plays_till_broke <- funtion(start_with) {
    cash <- start_with
    n <- 0
    while( cash > 0) {
      cash <- cash -1 + play()
      n <- n + 1
    }
    n
}

#start_with = 100, n 为 200多次, 所以不要赌博!

9.5 repeat循环

play_till_broke <- function(start_with)
    cash <- start_with
    n <- 0
    repeat {
      cash <- cash - 1 + play()
      n <- 1
      if (cash <= 0) {
        break
      }
    }
    n
}

9.6 小结

replicate 函数也可以实现循环。循环代码速度慢。

实现重复性任务的自动化对于数据科学来说意义重大。它是模拟的基石,也是估计方差和概率的基础。

for会遍历循环输入集合中的所有元素,每次都运行一遍指定的代码段 。如果要保存循环的输出结果,就需要在循环运行之前创建好一个对象,并在循环代码中将想要保存的结果存储在这个对象之中。

第十章 代码提速

10.1 向量化代码

L <- rep(c(100, -100), 1000000)
abs1 <- function(vec) {
  for(i in 1:length(vec)){
    if(vec[i] < 0) {
      vec[i] <- -vec[i]
    }
  }
  vec
}
abs2 <- function(vec) {
  negs <- vec <0
  vec[negs] <- vec[negs] * -1
  vec
}
system.time(abs1(L))
system.time(abs2(L))

abs2是向量化代码,运用到R的三大法宝:逻辑运算、取子集和元素方式执行。

这里面有许多可以学习的点,就不写了,可以通过读代码学习。 

10.2 如何编写向量化代码

(1)对于程序中的有序步骤,使用向量化的函数来完成

(2)对于同类情况,使用逻辑值取子集的方式来处理。尝试一次性处理完成一类情况中的所有元素。a [ x == "A" ] <- "B"

(3)if与for同时出现时往往可以被向量化代码替代。if是一个单独动作,这意味着它常与for循环同时出现,而这种结构可以被逻辑值取子集的方式取代。

(4)查找表也是一种向量化的方法

10.3 如何在R中编写快速的for循环

(1)能放在循环外的代码就不放在循环内

(2)确保用来存储循环结果的对象必须具备足够的容量,否则R要在循环过程中不断地复制向量,在内存中删除旧版的向量,再找到新向量存放该向量的新版本。这样很慢。

如果某些函数的源代码中出现诸如.Primitive, .Internal, .Call时,可以基本确信这些函数调用了其他语言编写的代码,具有外部语言带来的速度优势。

10.4 向量化编程实战

书上有大段的代码,不方便展示。但很重要。

10.5 小结

逻辑测试、取子集和元素方式执行。

有些任务是无法被向量化的。

如果只是完成一件事,虽然for慢,但是写得快;向量化代码写得可能慢,但是跑的快;自己权衡。

10.6 项目3总结

很重要,自己去看书。然后就是推荐姊妹篇:R for Data Science。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星星的小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值