Menu

R 语言如何重命名列(names、colnames、dplyr rename)

在 R 中重命名数据框的列:names() 和 colnames(),按位置与按名字重命名,setNames(),dplyr 的 rename(),以及清理导入数据中杂乱的表头。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

先看看列名:names() 和 colnames()

列名保存在一个属性中,你可以像读取任何向量一样读取它。对于数据框,names() 和 colnames() 都会返回它:

结果一样。唯一真正的区别是:colnames() 也能用于矩阵,而 names() 不行,所以通用的代码会用 colnames()。在日常的数据框上,两者可以互换。

理解下面所有内容的关键是:重命名列就是给这个向量赋值。 基础 R 没有专门的重命名函数;你用操作任何向量时都会用的索引方式来修改 names(df)。

按位置重命名(能用,但脆弱)

按位置索引列名向量,然后赋值:

第 2 列现在叫 price 了。在交互式环境里快速改一下没问题,但在脚本里就是个陷阱。位置是对列顺序的一种承诺,而列顺序恰恰是导入数据中最不稳定的东西:一旦你读取的 CSV 多出一列,names(df)[2] 就会悄悄地重命名错误的列。如果脚本按位置重命名,数据结构一变它就会出错,而且没有任何错误信息。

按名字重命名(稳妥的基础 R 写法)

匹配旧名字,而不是依赖位置:

先看内层部分:names(sales) == "prc" 会产生 FALSE TRUE FALSE,也就是列名向量上的一个逻辑掩码。用它做索引就能选出匹配的那一项,然后赋值替换它。如果 "prc" 不存在,就什么都不匹配,什么也不会改变(不会报错,所以要检查结果)。这种写法不怕列被重新排序、不怕新增列,复制粘贴到其他脚本里也照样能用。把它记住,这就是基础 R 对“重命名一列”的标准答案。

一次重命名多列

如果要给每一列都命名(导入数据后经常需要这样做),就替换整个向量;如果只重命名选中的部分列,就用 match():

match(old, names(df)) 返回旧名字所在的位置,所以新名字会准确地放到旧名字原来的位置上,和单个名字的写法一样,不受顺序影响。如果某个旧名字不存在,match() 会返回 NA,赋值就会报错,这正是你想要的失败方式:明确地报错。

管道中用 setNames()

上面所有的写法都要分两步修改一个变量。setNames(object, names) 在一个表达式中返回重命名后的副本,这正是管道需要的:

当某个函数返回的数据框没有列名或列名不好,而你想直接在行内修好它时,这就很方便,比如 read_something() |> setNames(c("id", "value")),不需要临时变量。

dplyr 的方式:rename() 和 rename_with()

dplyr 的 rename() 接受 new = old 这样的配对,新名字在前,每个人都会至少弄反一次(以下是静态代码,沙盒只运行基础 R):

library(dplyr)

sales |> rename(price = prc, qty = q)

调用中没有涉及的旧名字保持不变,而拼错的旧名字会直接报错,而不是悄悄地什么都不做,这是相对于基础 R 写法的实实在在的改进。如果要按规则而不是按配对来重命名,rename_with() 会把一个函数应用到列名上:

sales |> rename_with(toupper)                          # every column
sales |> rename_with(toupper, starts_with("p"))        # just some

这些函数如何融入 dplyr 的动词家族,请参阅 dplyr 入门。

清理导入数据中杂乱的表头

真实的 CSV 表头往往是 "Order ID"、"unit.price ($)"、"2024 Total" 这样的,名字里有空格和符号,导致到处都得用反引号括起来。基础 R 的 make.names() 能把任何字符向量转换成合法的 R 名字:

合法是合法了,但也有它自己的难看之处(X2024.Total)。这就是为什么很多团队统一使用 janitor 包的 clean_names(),一次调用就能生成整齐的 snake_case(order_id、unit_price、x2024_total):df |> janitor::clean_names()。如果你每周都要导入杂乱的文件,它立刻就能回本。

要点回顾

  • 列名只是一个向量:用 names()/colnames() 读取,给它赋值就能重命名。
  • names(df)[2] <- "new" 很脆弱;names(df)[names(df) == "old"] <- "new" 才是要记住的写法。
  • match() 按名字重命名多列;setNames() 在管道中直接重命名。
  • dplyr 的 rename(new = old) 遇到不存在的名字会报错(这是好事),rename_with() 按规则重命名。
  • 处理杂乱的导入表头:基础 R 用 make.names(),想要漂亮的结果就用 janitor::clean_names()。

下一篇:排序,向量用 sort(),数据框用 order() 技巧,还有 arrange()。

常见问题

R 中怎么重命名一列?

稳妥的基础 R 写法是按名字匹配:names(df)[names(df) == "old"] <- "new"。不管名为 old 的列在什么位置,它都能找到并重命名。在 dplyr 中是 rename(df, new = old),注意顺序:新名字在前。

names() 和 colnames() 有什么区别?

在数据框上,实际没有区别:两者都能读取和设置列名。colnames() 还能用于矩阵(names() 不行),所以需要同时处理两者的代码往往用 colnames()。在普通数据框上,用哪个都行。

R 中怎么按位置重命名一列?

给列名向量中对应的位置赋值:names(df)[2] <- "price" 会重命名第二列。这样能用,但很脆弱:一旦新增了一列,或者 CSV 改变了列的顺序,第 2 个位置就是另一列了。优先按名字重命名。

R 中怎么一次重命名多列?

赋值一个完整的向量:names(df) <- c("id", "name", "price") 会按顺序替换所有列名。要按名字只重命名选中的几列,用 match():names(df)[match(c("old1", "old2"), names(df))] <- c("new1", "new2")。在 dplyr 中:rename(df, new1 = old1, new2 = old2)。

Coddy 编程语言插图

和 Coddy 一起学编程

开始