Подтвердить что ты не робот

Переименуйте один столбец с именем в R

Я хочу обновить один столбец фрейма данных, ссылаясь на него с использованием его первоначального имени, возможно ли это? Например, скажем, что у меня были данные таблицы

a b c  
1 2 2  
3 2 3  
4 1 2

и я хотел обновить имя столбца b до 'd'. Я знаю, что могу использовать

colnames(data)[2] <- 'd'  

но могу ли я внести изменения, конкретно ссылаясь на b, то есть на что-то вроде

colnames(data)['b'] <- 'd'  

так что, если упорядочение столбцов в кадре данных изменится, правильное имя столбца будет по-прежнему обновляться.

Заранее спасибо

4b9b3361

Ответ 1

По состоянию на октябрь 2014 года это теперь можно легко сделать в пакете dplyr:

rename(data, d = b)

Ответ 2

Существует функция 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.

Ответ 3

Это похоже на хак, но первое, что приходило в голову, заключалось в том, чтобы использовать 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

Ответ 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, либо еще лучше сделайте простой colnames(d) == "b", как предлагал @joran. Соответствие регулярных выражений будет всегда медленнее, чем ==, поэтому для простых задач, подобных этому, вы можете использовать простой ==.