如何在 R 中创建变量
R 中的变量就是绑定到某个值上的名字。用赋值箭头 <- 来创建变量:名字写在箭头前面,值写在箭头后面。
三个变量,三种不同的值,而且没有任何类型声明,R 会根据值本身推断类型(详见数据类型)。变量一旦存在,任何可以用这个值的地方都可以用它:
重新赋值也是一样。只要再赋一次值,变量就会欣然换成新的值,甚至换成新的类型:
字符串变成数字,R 并没有报错。这种灵活性很方便,但如果一个变量的含义在脚本中途发生了变化,通常就说明你应该换一个新名字了。
为什么 R 用 <- 而不是 =
这是每个人都会问的问题:age = 30 也能用,为什么每本 R 书、每份风格指南、每个包都用箭头?
因为 R 中的 = 根据出现位置的不同,代表两种不同的东西。在顶层,它表示赋值。在函数调用内部,它按名称匹配参数,不会创建变量:
如果你写成 mean(values, na.rm <- TRUE),就会意外地创建一个名为 na.rm 的全局变量,并按位置传入 TRUE:语法合法,结果错误,而且很难发现。让代码保持可读的惯例很简单:
<-永远表示赋值。=永远表示“这个参数取这个值”,用在函数调用内部。
遵循这个分工,你读到的每一行 R 代码都能一眼看出是在创建东西还是在传递东西。这是 R 世界里最普遍的一条风格规则,RStudio 甚至专门给 <- 设了一个快捷键(Alt+-)。
少用的“亲戚”:->、= 和 assign()
R 还有另外两种赋值方式,即使你很少写,也值得认识。
反向箭头 -> 按相反方向赋值,值在前,名字在后:
你偶尔会在长管道的末尾看到它(“把这些都算完,然后存起来”),但大多数风格指南建议避免使用:读者习惯在行首寻找被定义的名字。
assign() 用一个字符串来创建变量,这意味着名字可以在运行时拼出来:
这看起来很巧妙,但几乎总是用错了工具:一组编号的变量,其实就是伪装起来的向量或列表。只有在名字确实必须计算出来时才使用 assign();与它配对的 get("score") 可以按字符串名字读取变量。
命名规则
R 接受满足以下条件的名字:
- 由字母、数字、点号(
.)和下划线(_)组成。 - 以字母开头,或以后面不跟数字的点号开头。
- 不是保留字(
if、for、TRUE、NULL、function等少数几个)。
所以下面这些都是合法的:
而下面这些不合法:
2nd_user:不能以数字开头。_temp:也不能以下划线开头(这一点和 Python 不同)。user-name:连字符是减号,不能用在名字里。TRUE:保留字。
名字区分大小写:total、Total 和 TOTAL 是三个互不相关的变量,你打错字时 R 会直接创建新变量,不会给出任何警告。
列出和删除:ls() 和 rm()
你创建的每个变量都会进入工作空间(即全局环境)。ls() 列出其中的内容,rm() 用来删除:
有两个细节值得了解。第一,rm(list = ls()) 会清空整个工作空间,在探索性会话的开头很方便,在其他地方则具有破坏性。第二,以点号开头的名字(例如 .cache)不会出现在 ls() 的结果中,除非调用 ls(all.names = TRUE),这与 Unix 中隐藏文件的惯例相同。
命名惯例:使用 snake_case
除了硬性规则,现代 R 社区(以及 tidyverse 风格指南)已经形成了一些惯例:
- 变量和函数用
lower_snake_case:retry_count、fit_model。 - 名字中的点号合法但已过时:基础 R 里满是
data.frame时代的名字,比如my.data,但点号在 R 的 S3 方法系统中也有含义(print.data.frame表示“数据框的 print 方法”),所以新代码会避免使用点号。 - 不用匈牙利命名前缀,也不用 camelCase:在较老的包里你会看到
camelCase,但整个生态已经统一到 snake_case。 - R 没有真正的常量;惯例是用大写字母命名打算当作常量的变量(
MAX_RETRIES <- 5),并且不再重新赋值。
选择有描述性的名字,并保持一致。avg_score 比 as 多敲四个键,却能让以后的每位读者都不必翻回脚本前面去查。
本节要点
name <- value创建变量;社区约定=只用于函数参数。->和assign()确实存在;你读到它们的次数应该多于你写它们的次数。- 名字由字母、数字、点号和下划线组成;不能以数字或下划线开头,并且区分大小写。
ls()查看工作空间,rm()清理工作空间。- 写
snake_case,你的代码就会和如今大家写的 R 代码风格一致。
下一节:这些变量到底能存放哪些类型的值,包括数值型、整数型、字符型和逻辑型。
常见问题
R 中如何创建变量?
写下变量名、赋值箭头 <- 和值:age <- 30。R 会根据值推断类型,不需要声明。在顶层写 age = 30 也可以,但社区惯例是用 <-。
R 中 <- 和 = 有什么区别?
在脚本的顶层,两者作用相同。但在函数调用内部就不一样了:mean(x, na.rm = TRUE) 用 = 按名称匹配参数,而不是创建变量。由于 = 会根据上下文扮演两种角色,R 的风格指南约定 <- 只用于赋值,= 只用于参数。
R 中如何删除变量?
rm(x) 会从工作空间中删除变量 x。rm(list = ls()) 会删除所有变量,想从头开始时很有用,分析进行到一半时则很危险。ls() 列出当前存在的变量。
R 的变量名可以包含点号吗?
可以,my.data 是完全合法的名字,较老的 R 代码到处都在用点号。现代风格更推荐下划线(my_data),因为点号在 R 的 S3 方法系统中也有含义,带点号的名字读起来容易产生歧义。