Ответ 1
По состоянию на октябрь 2014 года это теперь можно легко сделать в пакете dplyr:
rename(data, d = b)
Я хочу обновить один столбец фрейма данных, ссылаясь на него с использованием его первоначального имени, возможно ли это? Например, скажем, что у меня были данные таблицы
a b c
1 2 2
3 2 3
4 1 2
и я хотел обновить имя столбца b до 'd'. Я знаю, что могу использовать
colnames(data)[2] <- 'd'
но могу ли я внести изменения, конкретно ссылаясь на b, то есть на что-то вроде
colnames(data)['b'] <- 'd'
так что, если упорядочение столбцов в кадре данных изменится, правильное имя столбца будет по-прежнему обновляться.
Заранее спасибо
По состоянию на октябрь 2014 года это теперь можно легко сделать в пакете dplyr:
rename(data, d = b)
Существует функция setnames
, встроенная в пакет data.table
для этого.
setnames(DT, "b", "d")
Он изменяет имена по ссылке без копирования вообще. Любой другой метод, использующий names(data)<-
или names(data)[i]<-
или аналогичный, будет копировать весь объект, как правило, несколько раз. Несмотря на то, что все, что вы делаете, это изменение имени столбца.
DT
должен быть тип data.table
для setnames
для работы. Поэтому вам нужно переключиться на data.table
или преобразовать с помощью as.data.table
, чтобы использовать его.
Вот выдержка из ?setnames
. Предполагается, что вы запускаете example(setnames)
в приглашении, а затем комментарии относятся к копиям, которые вы видите в сообщении 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.
Это похоже на хак, но первое, что приходило в голову, заключалось в том, чтобы использовать 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
Как указывает Йоран ниже, я слишком усложнил ситуацию... нет необходимости в регулярном выражении. Это также сохраняет несколько символов при вводе текста.
colnames(dat)[colnames(dat) == "foo"] <- "bar"
#------
a bar c
1 1 1 1
2 2 2 2
3 3 3 3
Да, но это сложнее (насколько я знаю), чем числовое индексирование. Я собираюсь предоставить грязную функцию, которая сделает это, и если вы хотите увидеть, как это сделать, просто раздирайте функцию по строкам:
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')
Я не согласен с @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
, либо еще лучше сделайте простой colnames(d) == "b"
, как предлагал @joran. Соответствие регулярных выражений будет всегда медленнее, чем ==
, поэтому для простых задач, подобных этому, вы можете использовать простой ==
.