重命名 R 中的一个命名列
Posted
技术标签:
【中文标题】重命名 R 中的一个命名列【英文标题】:Rename one named column in R 【发布时间】:2012-05-18 15:25:52 【问题描述】:我想更新数据框的一列,使用其原始名称引用它,这可能吗?例如说我有表“数据”
a b c
1 2 2
3 2 3
4 1 2
我想将 b 列的名称更新为“d”。我知道我可以使用
colnames(data)[2] <- 'd'
但我可以通过专门引用 b 来进行更改,即类似
colnames(data)['b'] <- 'd'
这样,如果数据框的列顺序发生变化,正确的列名仍会更新。
提前致谢
【问题讨论】:
好问题!正在尝试这个:colnames(data['b']) <- 'd'
,也不好!正如蔡斯指出的那样,这就是方式:colnames(data)[colnames(data) == "b"] <- "d"
【参考方案1】:
有一个函数 setnames
内置在包 data.table
中。
setnames(DT, "b", "d")
它通过引用更改名称,根本没有副本。使用names(data)<-
或names(data)[i]<-
或类似方法的任何其他方法都会复制整个 对象,通常是多次。即使您所做的只是更改列名。
DT
必须输入 data.table
才能使 setnames
工作。所以你需要切换到data.table
或使用as.data.table
转换,才能使用它。
这是来自?setnames
的摘录。目的是您在提示符下运行 example(setnames)
,然后 cmets 与您看到的 tracemem
报告的副本相关。
DF = data.frame(a=1:2,b=3:4) # base data.frame to demo copies
tracemem(DF)
colnames(DF)[1] <- "A" # 4 copies of entire object
names(DF)[1] <- "A" # 3 copies of entire object
names(DF) <- c("A", "b") # 2 copies of entire object
`names<-`(DF,c("A","b")) # 1 copy of entire object
x=`names<-`(DF,c("A","b")) # still 1 copy (so not print method)
# What if DF is large, say 10GB in RAM. Copy 10GB just to change a column name?
DT = data.table(a=1:2,b=3:4,c=5:6)
tracemem(DT)
setnames(DT,"b","B") # by name; no match() needed. No copy.
setnames(DT,3,"C") # by position. No copy.
setnames(DT,2:3,c("D","E")) # multiple. No copy.
setnames(DT,c("a","E"),c("A","F")) # multiple by name. No copy.
setnames(DT,c("X","Y","Z")) # replace all. No copy.
【讨论】:
但是为了简单的列重命名而加载新包值得所有的喧嚣吗? =) 绝对。它可以在out of memory
之间产生差异,或者不是。而且它更短、更容易,而且出现错误的机会也更少。
@Tyler 在 r-devel 上有两个(相当长的)线程:speeding up perception 和(可能是最相关的)confused about NAMED 和可能其他。
@Tyler 现在在这些显示 data.table 速度较慢的基准上,你能指点我一个吗?
@MatthewDowle -- 刚刚在您的示例中添加了一个 tracemem
测试,只是 b/c 变量 R 的行为有点搞笑,而且 b/c 我有点喜欢倒计时4, 3, 2, 1, ... data.table
.【参考方案2】:
截至 2014 年 10 月,现在可以在 dplyr 包中轻松完成此操作:
rename(data, d = b)
【讨论】:
【参考方案3】:这似乎是一个 hack,但首先想到的是使用 grepl()
和足够详细的搜索字符串,以便只获取您想要的列。我相信还有更好的选择:
dat <- data.frame(a = 1:3, b = 1:3, c = 1:3)
colnames(dat)[grepl("b", colnames(dat))] <- "foo"
dat
#------
a foo c
1 1 1 1
2 2 2 2
3 3 3 3
正如 Joran 在下面指出的那样,我把事情复杂化了……根本不需要正则表达式。这也节省了打字时的一些字符。
colnames(dat)[colnames(dat) == "foo"] <- "bar"
#------
a bar c
1 1 1 1
2 2 2 2
3 3 3 3
【讨论】:
或者你可以简单地使用colnames(dat) == 'b'
索引列名,但不管你做什么,它都会是循环的。
不要将正则表达式用于这样的简单内容。我宁愿坚持使用简单的==
关系运算符。
乍一看,我认为 Chase 使用了agrep
,这可能有一些优势。
@aL3xa,如果您有许多相似的列前缀/后缀要重命名,gsub
非常宝贵。但是,一个孤立的案例通常是矫枉过正的。【参考方案4】:
是的,但它比数字索引更难(据我所知)。我将提供一个脏函数来执行此操作,如果您想了解如何执行此操作,只需逐行撕开该函数:
rename <- function(df, column, new)
x <- names(df) #Did this to avoid typing twice
if (is.numeric(column)) column <- x[column] #Take numeric input by indexing
names(df)[x %in% column] <- new #What you're interested in
return(df)
#try it out
rename(mtcars, 'mpg', 'NEW')
rename(mtcars, 1, 'NEW')
【讨论】:
【参考方案5】:我不同意@Chase - grepl
解决方案不是最幸运的解决方案。我会说:选择简单的==
。原因如下:
d <- data.frame(matrix(rnorm(100), 10))
colnames(d) <- replicate(10, paste(sample(letters[1:5], size = 5, replace=TRUE, prob=c(.1, .6, .1, .1, .1)), collapse = ""))
现在试试grepl("b", colnames(d))
。要么通过fixed = TRUE
,或者更好地像@joran 建议的那样做简单的colnames(d) == "b"
。正则表达式匹配总是比==
慢,所以对于像这样的简单任务,您可能需要使用简单的==
。
【讨论】:
我想我在回答中指出我确信有更好的答案,特别是I'm sure there are better options
部分。正如 Joran 在 cmets 中指出的那样,直接使用 ==
更好,我现在也认识到并在我的答案中展示了一个示例:) 为了后代,我将保留上半部分。
这个答案与我的基本相同,因为我使用colnames(d) %in% "b"
。在这种情况下,他们正在做同样的事情,尽管我认为==
会更快。以上是关于重命名 R 中的一个命名列的主要内容,如果未能解决你的问题,请参考以下文章