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

R data.table change R names

Я создал небольшие data.table DT = data.table(a=1:2, a=1:2).

Если я использую names(DT) <- c("b","b")

Я получаю предупреждение

In `names<-.data.table`(`*tmp*`, value = c("b", "b")) :
  The names(x)<-value syntax copies the whole table. This is due to <- in R itself. Please change to setnames(x,old,new) which does not copy and is faster. See help('setnames'). You can safely ignore this warning if it is inconvenient to change right now. Setting options(warn=2) turns this warning into an error, so you can then use traceback() to find and change your names<- calls.

Но если я использую setnames(DT, names(DT), c("b","b"), тогда я получаю ошибку

Error in setnames(DT, names(DT), c("b", "b")) : 
  Some duplicates exist in 'old': a

Если тот же пример используется с data.frame, чем DT = data.frame(a=1:2, a=1:2), и используйте names(DT) <- c("b","b"), тогда я не получаю ошибки.

4b9b3361

Ответ 1

Не предоставляйте old и new, и у вас не будет проблем. Однако это не проблема. В base::data.frame вы не можете иметь столбцы с тем же именем, что...

#  What you actually get...
DT = data.frame(a=1:2, a=1:2); names(DT)
#[1] "a"   "a.1"

Но кажется, что в data.table вы можете иметь столбцы с тем же именем...

DT = data.table(a=1:2, a=1:2); names(DT)
[1] "a" "a"

Но setnames выдает ошибку, я думаю, потому что он не знает, к какому столбцу a относится, когда оба столбца называются a. Вы не получаете ошибки при переходе data.frame в data.table, потому что у вас нет дублированных имен столбцов.

Во-первых, я бы сказал, что не создавайте столбцы с тем же именем, это очень плохое, если вы планируете использовать программный код data.table (но, как @MatthewDowle указывает на комментарии, это выбор дизайна, чтобы предоставить пользователю максимальную свободу в data.table).

Если вам нужно это сделать, используйте setnames только с приведенным аргументом old, который будет фактически рассматриваться как имена new, если new не указан. Если вы передаете имена old и вектор новых имен, старые имена будут найдены, а те, которые были изменены на соответствующее новое имя (так что old и new должны быть одинаковой длины, когда setnames используется с 3 параметры). setnames поймает любые двусмысленности с помощью:

if (any(duplicated(old))) 
           stop("Some duplicates exist in 'old': ", paste(old[duplicated(old)],
                collapse = ","))
if (any(duplicated(names(x)))) 
           stop("'old' is character but there are duplicate column names: ", 
                paste(names(x)[duplicated(names(x))], collapse = ",")) 

Когда поставляется только old setnames переназначает имена из old в столбцы столбца DT по столбцам с помощью .Call(Csetcharvec, names(x), seq_along(names(x)), old), поэтому от первого до последнего...

DT = data.table(a=1:2, a=1:2)
setnames(DT, c("b","b") )
DT
#   b b
#1: 1 1
#2: 2 2

Дополнение от Матфея по просьбе. В ?setnames есть некоторый фон:

Это не хорошая практика программирования, в общем, использовать номера столбцов а не имен. Вот почему setkey и setkeyv принимают только столбец имена и почему старые в setnames() рекомендуются для имен. если ты используйте номера столбцов, тогда ошибки (возможно, молчание) могут более легко ползти в ваш код с течением времени, если изменения сделаны в другом месте ваш код; например, если вы добавите, удалите или измените порядок столбцов за несколько месяцев время, номер набора по столбцу будет ссылаться на другой столбец, возможно, возвращать неверные результаты без предупреждения. (Похожий концепция существует в SQL, где "select * from..." считается бедным стиль программирования, когда требуется надежная, поддерживаемая система.) Если вы действительно хотите использовать номера столбцов, это возможно, но преднамеренно немного сложнее; например, setkeyv (DT, colnames (DT) [1: 2]).

[По состоянию на июль 2017, примечание выше больше не отображается в ?setnames, но проблема обсуждается в верхней части FAQ, vignette('datatable-faq').]

Таким образом, идея setnames заключается в том, чтобы с легкостью изменить имя столбца по имени.

setnames(DT, "oldname", "newname")

Если "oldname" не является именем столбца или не существует какой-либо двусмысленности в отношении того, что вы намерены (либо в данных сейчас, либо через несколько месяцев после того, как ваши коллеги изменили исходную базу данных или другой код вверх по течению или передали свои собственные данные к вашему модулю), то data.table поймает его для вас. Это на самом деле довольно сложно сделать в базе так же легко, как и setnames (включая проверки безопасности).

Ответ 2

И, setnames можно использовать для изменения сразу нескольких имен столбцов:

setnames (DT, old = c ( "oldname1", "oldname2", "oldname3" ), new = c ( "newname1", "newname2", "newname3" ))