添加一列:df$new <- value
在 base R 中添加一列,只需给一个还不存在的名称赋值。这个值通常是根据已有的列计算出来的:
这里发生了两件事。orders$total 得到了一个完整的向量:price * qty 会一次性为每一行计算,因为 R 中的算术运算是向量化的。orders$currency 得到的是单个值,R 把它循环补齐到了全部四行。其他任何长度都会报错(replacement has 3 rows, data has 4),这是 R 在防止你得到一个错位的列。
之所以能这样做,是因为数据框是由等长的列组成的列表,给它赋值一个新的命名元素,列表就会变长。数据框文档详细讲解了这个模型。
条件列:ifelse()
值取决于某个条件的列,要用 ifelse(),它是 if 的向量化版本。它接收一整个条件向量,并为每一行返回一个值:
为什么不用普通的 if?因为 if 只能求值恰好一个 TRUE/FALSE,交给它一整列就会报错(the condition has length > 1)。ifelse(test, yes, no) 会检查每个元素,并逐行做出选择。结果有三种或更多时,可以嵌套:
嵌套两层没问题;嵌套三层或更多就会变成金字塔,而这正是 dplyr 的 case_when()(见下文)要解决的问题。只针对单个值的 if/else 本身,请参阅 if-else 文档。
一次添加多列:transform()
base R 的 transform() 可以在一次调用中添加多列,并且直接使用列名:
注意 transform() 返回的是一个新的数据框,你必须把结果赋值回去;而 df$new <- ... 是直接原地修改。它有一个限制:同一次 transform() 调用中的表达式彼此看不见,所以在这里写 discount = ifelse(total > 50, ...) 会失败(total 还不存在)。分两步来做,或者改用允许这样写的 mutate()。
修改与创建
同样的赋值语法也会覆盖已有的列,唯一的区别在于这一列是否已经存在:
这一点值得停下来想想:覆盖一列时,R 不会给你任何警告。像 df$prise <- round(df$price, 2) 这样的拼写错误,会悄悄创建一个新列,而不是修正原来的列。完成转换后,用 print() 或 str() 看一下数据框,确认你改的就是你想改的。
删除一列
赋值 NULL 即可删除:
这一列就没了,不需要任何繁琐步骤。要删除多列,df[, c("a", "b")](保留你列出的列)通常比重复赋值 NULL 更清晰。
dplyr 的写法:mutate()
在 dplyr 中,完成以上所有操作的动词是 mutate()。下面的代码片段是静态的(沙盒只运行 base R),但同样的操作就是这样写的:
library(dplyr)
orders |>
mutate(
total = price * qty,
big = total > 50 # can use total, defined one line up
)
它比 base R 有两个优势。第一,在同一个 mutate() 中定义的列可以按顺序相互引用,这正是 transform() 不允许的。第二,它的条件辅助函数比嵌套的 ifelse() 更好用:
students |>
mutate(
grade = if_else(score >= 60, "pass", "fail"),
band = case_when(
score >= 85 ~ "high",
score >= 60 ~ "mid",
.default = "low"
)
)
if_else() 是更严格的 ifelse()(两个分支必须是同一种类型,能抓住真正的 bug)。case_when() 读起来就像一组扁平的 condition ~ value 配对,从上到下依次检查,.default 作为兜底,是 ifelse() 金字塔的易读替代品。和所有 dplyr 动词一样,mutate() 返回一个新的数据框;它如何与其他动词串联,见 dplyr 入门。
要点回顾
df$new <- expression添加一列;表达式会一次性对每一行运行。ifelse(test, yes, no)用来构造条件列;普通的if做不到。transform()一次调用可以添加多列,但这些列彼此看不见;mutate()则可以。- 同样的赋值会悄悄覆盖已有列:转换之后检查一下拼写。
df$col <- NULL删除一列;case_when()取代嵌套的ifelse()金字塔。
下一篇:重命名列,包括 names()、稳健的 base R 惯用法,以及 dplyr 的 rename()。
常见问题
R 语言怎么给数据框添加新列?
给一个还不存在的列名赋值:df$total <- df$price * df$qty。R 会当场创建这一列。值可以是单个值(循环补齐到每一行),也可以是由其他列计算出的向量,只要长度和行数一致即可。
R 语言怎么创建条件列?
使用向量化的 ifelse():df$grade <- ifelse(df$score >= 60, "pass", "fail") 会一次性检查每一行。不要用普通的 if,它只能处理单个条件,处理不了一整列。结果多于两种时,可以嵌套 ifelse() 调用,或者使用 dplyr 的 case_when()。
R 语言中 mutate() 有什么作用?
mutate() 是 dplyr 中用于添加或转换列的动词:df |> mutate(total = price * qty) 返回一个带有新列的数据框副本。它可以在一次调用中定义多个列,而且后面的列可以使用同一个 mutate 中前面定义的列。
R 语言怎么删除数据框中的列?
给它赋值 NULL:df$notes <- NULL 会直接删除这一列。在 dplyr 中,select(-notes) 返回一个不含该列的副本。