个人简介
- 作者简介:大家好,我是小白鹰,专注与医学相关的数据科学、机器学习和人工智能。
- 个人主页:星空下的小白鹰🦅
- 支持我:点赞 + 收藏 + 留言
- 系列专栏:
- 座右铭:宝剑锋从磨砺出,梅花香自苦寒来
目录
要举一反三。
第七章 程序
在function的花括号中使用print()函数可以显示函数内部生成的相关信息。
7.1 策略
策略可以理解为流程图里选择串联还是并联。完成一个任务的简单的策略就是把它分成几个小的任务。
- 讲复杂的任务分解为一些简单的子任务
- 使用实例
- 用通俗的语言描述解决方案,然后将其转换为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。