Ответ 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
(включая проверки безопасности).