R语言编程 第一讲 变量与赋值
这个系列将系统性介绍R语言的理论与实践,R语言是专注应用统计与数据分析领域的最热门的开源语言,兼具函数编程与面向对象编程的特点。R语言的使用门槛非常低,如果只是用来估计特定模型,那么只需要输入输出会调包就可以了,但总要有人去写以及优化这些包,所以我们在使用R语言之前,有必要系统性学习一下R语言编程。
这个系列会先介绍一些R语言编程的基础,比如变量、向量、向量切片、分支与循环、函数、可视化等,然后再分别介绍R语言的函数编程与面向对象编程的内容,最后介绍元编程与其他编程技巧。希望接下来的这个学年能够完成这个系列!
R语言的变量名
- 变量名可以包含字母、数字、下划线_ 和点 .
- 变量名只能以字母或点开头,字母区分大小写
- 变量不能用关键字,比如if、for等
- 给任意符号串加上``可以无视一切规则
例1 奇怪但正确的变量名
> .c = 3
> `_fff` = 5
> `for` = 3
> for = 3
Error: unexpected '=' in "for ="
> _fff = 5
Error: unexpected input in "_"
赋值符号 <- 与 = 的区别
R语言中 <- 与 = 都是非常常用的赋值符号,但它们是有很大的区别的:
- x <- Obj 表示创造一个对象Obj,然后让变量x指向Obj;
- y = Obj 表示创造一个对象Obj,并把它赋值给变量y;
例2 <- 与 = 的区别
library(lobstr) # 使用lobstr包可以分析R语言运行的细节
x <- 1
y <- x
obj_addr(x)
obj_addr(y)
a = 1
b = 1
obj_addr(a)
obj_addr(b)
第一段代码创造了一个取值为1的对象,然后让变量x指向这个对象;并且让变量y指向变量x指向的地址,于是变量y也指向了这个对象,函数obj_addr()可以返回一个对象的地址,输出为
obj_addr(x)
[1] “0x2e164f19ae0”
obj_addr(y)
[1] “0x2e164f19ae0”
这说明变量x与变量y指向同一个地址,也就是取值为1的这个对象的地址。
第二段代码将1赋值给变量a,然后将1赋值给变量b,这两个1是分别创造的两个不同的对象,因此函数obj_addr()的输出为
obj_addr(a)
[1] “0x2e1663493b8”
obj_addr(b)
[1] “0x2e166349348”
这说明变量a与变量b并没有指向同一个地址。
大家可以自行尝试,把第一段代码中的y <- x改为y = x,效果和第二段代码就是一样的。
赋值符号 <- 的更多细节
Copy-on-Modify与Modify-in-Place
- Copy-on-Modify:多个变量指向同一个对象时,对其中一个变量进行修改时,R语言会在另一个内存地址上复制这个对象,然后在新对象上进行修改,最后让这个变量指向新内存地址;
- Modify-in-Place:只有一个变量指向一个对象时,对这个变量进行修改会直接在这个对象上进行修改;
例3 Copy-on-Modify vs Modify-in-Place
x <- c(1,2,3,4)
y <- x
y[[2]] <- 1
x
obj_addr(x)
y
obj_addr(y)
我们先来分析这段代码,首先用c()创造了一个向量对象,并让变量x指向这个对象,然后让变量y也指向这个对象;接下来把变量y指向的对象中的第二个位置的值改为1,神奇的事情就发生了!我们来看一下输出
> x
[1] 1 2 3 4
> obj_addr(x)
[1] "0x2e16fcc0558"
这两行的输出说明x指向的对象取值没有变;
> y
[1] 1 1 3 4
> obj_addr(y)
[1] "0x2e16fcc0648"
这两行的输出说明y指向了一个新的对象,并且新的对象取值变了。这个现象的学名叫做Copy-on-Modify,它其实是由R语言的一种保护机制所导致的,因为变量x和y指向同一个对象,为了避免对变量y做的修改引起变量x的变化,R语言实质上复制了一个取值相同的对象,修改这个对象的取值,然后让变量y指向这个新的对象,原来的对象会被Garbage Collector收集起来删除释放内存。这种保护机制的好处在于它可以避免同时修改指向同一个对象的变量,缺点在于增加了运算需要的时间(复制+修改+重新指向)。大家可以自行尝试&