Можно ли использовать псевдонимы data.frame в R

При работе с некоторыми стандартами данных было бы проще использовать несколько способов просмотра столбцов data.frame. В качестве одного конкретного примера, при работе с данными SDTM для клинических испытаний каждый тип данных (например, лаборатории или показатели жизненно важных функций) имеет столбец для временной точки с именем «LBTPT» для лабораторий и «VSTPT» для показателей жизненно важных функций. В идеале при загрузке данных я хотел бы иметь возможность ссылаться на этот столбец как на «LBTPT» или «TPT».

В частности, я хотел бы найти способ сделать что-то вроде следующей работы:

d <- data.frame(LBTPT=1:3)
d <- alias_column(d, TPT = "LBTPT")
d$TPT == d$LBTPT

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

А для бонусных баллов он будет работать по принципу «делай то, что я имею в виду» при взаимодействии с такими функциями, как merge, names<-, bind_rows и т. д.

Ваш пример на самом деле не дает мне понять, насколько это было бы полезно, учитывая, что каждый столбец в любом случае должен иметь уникальное имя. Как это было бы полезно?

joran 19.05.2018 17:28

Что вам нужно делать с данными? По сути, это парадигма пакетов tidyverse, где вы обращаетесь к голым именам столбцов при работе с фреймом данных.

camille 19.05.2018 18:31

Создавать псевдоним не нужно. Просто переименуйте столбец, используя базу R: names (r) <- ... или используя пакеты dplyr или data.table - в зависимости от того, что вы предпочитаете.

Katia 19.05.2018 18:50

Я знаю, что могу переименовать столбцы data.frame с помощью names(x) <- ... или dplyr::rename или других методов. Есть несколько причин для использования псевдонима: 1) пакеты, которые я не контролирую, ищут стандартное имя (например, «LBTPT»), в то время как новый код, который я пишу, было бы легче обобщить с помощью псевдонима ( например, "TPT") и 2) в другом примере сопоставление данных с исходным источником данных было бы проще с использованием как имени для соответствия стандартам (которое я не контролирую), так и имени из исходных данных (которое я не control) связаны.

Bill Denney 21.05.2018 14:15

Я считаю, что это невозможно. R имеет семантику копирования при изменении, и даже если вы можете связать переменную с двумя разными именами (и изначально она будет сохранена только один раз, т.е. каждое имя будет указывать на одну и ту же память), как только вы измените одно, R сделаю копию. Я не могу придумать, как этого избежать, особенно с чистым R.

Alexis 22.05.2018 22:42

@Alexis data.table может это сделать. Смотрите мой ответ.

Harlan Nelson 22.08.2019 22:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
3 168
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я собираюсь опровергнуть свой комментарий и привести пример, который потенциально может сработать, но это то, что некоторые (включая меня) назвали бы "ужасным взломом":

setClass("aliased.data.frame", contains = "data.frame")

make_alias <- function(original_name, alias) {
  # make sure lazy evaluation doesn't bite us
  force(original_name)
  force(alias)

  setMethod("$", signature(x = "aliased.data.frame"), function(x, name) {
    if (name == alias) name <- original_name
    x[[name]]
  })
}

В этом примере я, по сути, затеняю метод $, чтобы применить «сглаживание». Вы должны аналогичным образом определить любые общие шаблоны, которые должны поддерживать ваш псевдоним. Например, теперь это будет работать:

> make_alias("a", "b")
> adf <- new("aliased.data.frame", data.frame(a=1:2))
> adf$b
[1] 1 2
> adf$a == adf$b
[1] TRUE TRUE

Придется учесть сложные аспекты. Например, метод $ по умолчанию для фреймов данных выполняет частичное сопоставление:

> data.frame(aa=1:2)$a
[1] 1 2

Если вы используете скобки вместо знаков доллара для ссылки на столбец, это сработает:

d <- data.frame(LBTPT=1:3)
LBTPT = "LBTPT"
TPT = "LBTPT"

d[TPT] == d[LBTPT]

Боюсь, однако, что он отвечает всем вашим потребностям.

Ответ принят как подходящий

Я считаю, что вы можете сделать это с помощью R6 и активных привязок.

  • Методы R6 относятся к объектам, а не к дженерикам.
  • Объекты R6 изменяемы: обычная семантика копирования при изменении не применяется.

Имея это в виду, мы можем создать пример. Здесь мы создаем два представления набора данных радужной оболочки глаза, где мы получаем доступ к одному и тому же столбцу, используя два разных имени столбца. При изменении имени любого столбца будет обновлен общий набор данных частной радужной оболочки глаза.

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

nb. Надеюсь, это укажет вам правильное направление.

Пример R6 (здесь мы создаем два представления набора данных радужной оболочки глаза):

require(R6)
data(iris)

dataframe_factory <- R6Class(
  "dataframe_factory",
  portable = FALSE,
  lock_objects = FALSE,
  private = list(
    ..iris_data = iris
  ),
  active = list(
    # add the binding here
    Sepal.Length = function(x, ...) {
      if ( missing(x) ) {
        private$..iris_data$Sepal.Length
      } else {
        private$..iris_data$Sepal.Length[...] <<- x
      }
    },

    another.Sepal.Length = function(x, ...) {
      if ( missing(x) ) {
        private$..iris_data$Sepal.Length
      } else {
        private$..iris_data$Sepal.Length[...] <<- x
      }
    }
    )
)

# Create the DataFrame
my_Dataframe <- dataframe_factory$new()

# Retrieve the alias
my_Dataframe$Sepal.Length
my_Dataframe$another.Sepal.Length

my_Dataframe$Sepal.Length[1] <- 5
my_Dataframe$Sepal.Length[1]

my_Dataframe$another.Sepal.Length[2] <- 8
my_Dataframe$another.Sepal.Length[2]

my_Dataframe$Sepal.Length
my_Dataframe$another.Sepal.Length

head(my_Dataframe$Sepal.Length,2)
my_Dataframe$Sepal.Length[1:2]

identical(my_Dataframe$Sepal.Length, my_Dataframe$another.Sepal.Length)
identical(my_Dataframe$Sepal.Length[1], my_Dataframe$another.Sepal.Length[1])
identical(my_Dataframe$Sepal.Length[1:2], my_Dataframe$another.Sepal.Length[1:2])

Вывод консоли R6 на консоль:

> require(R6)

> data(iris)

> dataframe_factory <- R6Class(
+   "dataframe_factory",
+   portable = FALSE,
+   lock_objects = FALSE,
+   private = list(
+     ..iris_data = iris
 .... [TRUNCATED] 

> # Create the DataFrame
> my_Dataframe <- dataframe_factory$new()

> # Retrieve the alias
> my_Dataframe$Sepal.Length
  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1
 [21] 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4 5.1
 [41] 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2
 [61] 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7
 [81] 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7
[101] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0
[121] 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9
[141] 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

> my_Dataframe$another.Sepal.Length
  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1
 [21] 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4 5.1
 [41] 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2
 [61] 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7
 [81] 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7
[101] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0
[121] 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9
[141] 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

> my_Dataframe$Sepal.Length[1] <- 5

> my_Dataframe$Sepal.Length[1]
[1] 5

> my_Dataframe$another.Sepal.Length[2] <- 8

> my_Dataframe$another.Sepal.Length[2]
[1] 8

> my_Dataframe$Sepal.Length
  [1] 5.0 8.0 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1
 [21] 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4 5.1
 [41] 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2
 [61] 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7
 [81] 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7
[101] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0
[121] 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9
[141] 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

> my_Dataframe$another.Sepal.Length
  [1] 5.0 8.0 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1
 [21] 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0 5.5 4.9 4.4 5.1
 [41] 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5 6.5 5.7 6.3 4.9 6.6 5.2
 [61] 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7
 [81] 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7
[101] 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0
[121] 6.9 5.6 7.7 6.3 6.7 7.2 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9
[141] 6.7 6.9 5.8 6.8 6.7 6.7 6.3 6.5 6.2 5.9

> head(my_Dataframe$Sepal.Length,2)
[1] 5 8

> my_Dataframe$Sepal.Length[1:2]
[1] 5 8

> identical(my_Dataframe$Sepal.Length, my_Dataframe$another.Sepal.Length)
[1] TRUE

> identical(my_Dataframe$Sepal.Length[1], my_Dataframe$another.Sepal.Length[1])
[1] TRUE

> identical(my_Dataframe$Sepal.Length[1:2], my_Dataframe$another.Sepal.Length[1:2])
[1] TRUE

Это было основой того, как я начал свой код ниже. Спасибо!

Bill Denney 24.05.2018 15:58

В итоге я использовал комбинацию стратегий из @ Technophobe01 и @Alexis для создания следующего решения:

library(methods)

setClass("dataframe_alias", representation=representation(data = "data.frame", aliases = "list"))

as.dataframe_alias <- function(x, aliases=list()) {
  new("dataframe_alias", data=as.data.frame(x), aliases=aliases)
}

as.data.frame.dataframe_alias <- function(x, ...) {
  x@data
}

`$.dataframe_alias` <- function(x, name) {
  x[[name]]
}

`[[.dataframe_alias` <- function(x, name, ...) {
  if (name %in% names(x@data)) {
    x@data[[name, ...]]
  } else if (name %in% names(x@aliases)) {
    x@data[[x@aliases[[name]], ...]]
  } else {
    stop(name, " is not a name or alias for the dataframe_alias.")
  }
}

names.dataframe_alias <- function(x) {
  ret <- names(x@data)
  attr(ret, "aliases") <- x@aliases
  ret
}

alias_or_name_to_name <- function(object, alias) {
  ret <- rep(NA_character_, length(alias))
  mask_original_name <- alias %in% names(object@data)
  mask_aliased_name <-
    !mask_original_name &
    alias %in% names(object@aliases)
  mask_no_name <- !(mask_original_name | mask_aliased_name)
  if (any(mask_no_name)) {
    stop("Some aliases are not recognized as an original or aliased name: ",
         paste(alias[mask_no_name], collapse = ", "))
  }
  ret[mask_original_name] <- alias[mask_original_name]
  ret[mask_aliased_name] <- unlist(object@aliases[alias])
  ret
}

#' Add an alias to a dataframe_alias
#' 
#' @param object A dataframe_alias object
#' @param ... named aliases to add in the form \code{alias=original_name}
#' @param rm Remove the alias(es)?
#' @return The updated \code{object}
#' @export
alias.dataframe_alias <- function(object, ..., rm=FALSE) {
  args <- list(...)
  if (is.null(names(args))) {
    stop("Arguments must be named")
  } else if (any(names(args) %in% "")) {
    stop("All arguments must be named")
  } else if (!all(unlist(args) %in% names(object))) {
    # all arguments must map to actual data names (indirect alises are not
    # currently permitted)
    browser()
    stop("All arguments must map to original data names")
  }
  for (nm in names(args)) {
    object@aliases[[nm]] <- args[[nm]]
  }
  object
}

foo <- as.dataframe_alias(iris, aliases=list(foo = "Sepal.Length"))
foo2 <- alias(foo, bar = "Sepal.Length")

Мне не было интуитивно понятно, как заставить некоторые из обычных функций извлечения хорошо работать с R6. В частности, когда я пытался записать [[.dataframe_alias, я продолжал получать ошибки. Вероятно, это было моим непониманием парадигмы R6.

Bill Denney 23.05.2018 15:10

@BillDenney У вас есть примерный набор операций и набор данных, которые вы пытаетесь использовать? Было бы полезно увидеть их. Я считаю, что вы могли бы создать здесь общий класс R6, чтобы делать то, что вы предлагаете.

Technophobe01 23.05.2018 17:49

Код, который я дал выше, не делает всего, что я хочу делать. Общий список операций, которые я ищу: извлечь ([, [[, $), установить (то же, что и extract), merge (сначала попробуйте сопоставить базовые имена, затем попробуйте сопоставить псевдонимы), rbindbind_rows), cbind. (и bind_cols), а в идеале - полный набор глаголов dplyr. (Я знаю, что прошу здесь луну.)

Bill Denney 24.05.2018 15:57

Билл, не беспокойся. Используйте набор данных радужной оболочки глаза (или один по вашему выбору) в качестве примера и покажите операции, которые вы хотите использовать с набором данных. Например, я хочу [Извлечь, проиндексировать и т. д.] И показать результат теста. Просто сделайте это с одним набором данных, а не с псевдонимом (я думаю, вы поймете, чего вы там хотите).

Technophobe01 24.05.2018 17:51

Редактировать

$.data.frame был удален из R между R 3.5 и R 3.6, поэтому вот новое решение:

df <- head(iris)
comment(df) <- c(SL = "Sepal.Length",SW = "Sepal.Width")

`$.data.frame` <- function(e1,e2) {
  if (e2 %in% names(comment(e1)))
     e2 <- comment(e1)[e2]
  eval.parent(substitute(as.list(e1)$e2))
}

df$SL
# [1] 5.1 4.9 4.7 4.6 5.0 5.4

identical(df$SL,df$Sepal.Length)
# [1] TRUE 

предыдущее решение

Вот действительно быстрый трюк с использованием функций / атрибутов comment и comment<- и функции trace:

df <- head(iris)
comment(df) <- c(SL = "Sepal.Length",SW = "Sepal.Width")
trace(`$.data.frame`,quote(if (name %in% names(comment(df)))
  name <- comment(df)[name]),print=FALSE)

df$SL
# [1] 5.1 4.9 4.7 4.6 5.0 5.4

identical(df$SL,df$Sepal.Length)
# [1] TRUE

атрибут комментария не печатается по умолчанию, как это делали бы другие, чтобы увидеть его, вызовите:

comment(df)

Отмените вызов trace с помощью:

 untrace(`$.data.frame`)

Это чище и короче моего решения. как можно заставить работать с <-?

Gwang-Jin Kim 09.06.2018 00:59

Я использую существующую функцию comment<- для создания атрибута комментария. Я мог бы определить любой другой атрибут, но здесь я использую тот факт, что этот конкретный аргумент не печатается по умолчанию.

Moody_Mudskipper 09.06.2018 02:47

В этом примере я получаю ошибку "объект не найден": Ошибка в методах ::. TraceWithMethods ($.data.frame, quote (if (name% in%: object '$ .data.frame' not found)

Steve Dutky 06.04.2021 20:21

Действительно, Стив, я смог воспроизвести это. Я считаю, что он был удален из R, см. Мое новое решение выше.

Moody_Mudskipper 06.04.2021 22:36

Пример из @ Technophobe01 хорош, но не очень практичен. Вы всегда должны писать для каждого псевдонима новую функцию и новое определение класса. Много работы!

Исходя из Лиспа, я думал о вашей проблеме. В Лиспе в таких случаях можно определить макросы для поиска псевдонимов. Самая крутая вещь - reader-macros. С помощью макросов-читателей вы можете изменить способ, которым интерпретатор Лиспа «видит» код. Чаще всего макросы читателя начинаются с #.

Однако мы не на Лиспе. Мы находимся в R. У нас нет этих возможностей.

Единственный способ в R позволить R "читать" выражение с другими правилами - это - либо переопределить метод $ (возможно, однажды я предложу это решение - или кто-то другой ... - но есть одно большое препятствие, что $ примитивный - нам не повезло ...), либо тогда: вы использовать функцию (в моем случае: with.alias() сокращено до: a() для alias), внутри которой изменяются правила. Я пошел по этому пути.

С моим решением вы можете сделать что-то вроде этого:

Как это будет работать

# your normal data frame definition
df <- data.frame(LBTPT = 1:3)

# now df contains:
df
##   LBTPT
## 1     1
## 2     2
## 3     3


# define your aliases for each data frame in this form:
define.alias(df, list("LBTPT" = "TPT"))
# within the `define.alias()` function, you give as the first argument
# the data frame symbol, for which aliases should be defined.
# the second argument is a list of "original name" = "alias" definitions.

# This is how you call your data frame with the alias name:
a(df$TPT) # returns what d$LBTPT returns  
         ## actually `with.alias` but shortened to: `a`
# call within `a()` or `with.alias()` the data frame with the aliased column name.
# the function then looks up in the attributes `aliases` of the data frame 
# the original name of the alias for the column and
# returns the value of the originally named column.

Определите всего три функции

Вот как вы определяете функции define.alias() и with.alias() и краткую форму a():

define.alias <- function(df, alias.list) {
  # revert definition list
  l <- names(alias.list)
  names(l) <- alias.list
  l <- as.list(l)

  # metaprogrammatically assign "aliases" attribute to data frame
  df <- substitute(df)
  alias.list <- substitute(l)
  eval(bquote(attr(.(df), "aliases") <- .(alias.list)), env = parent.env(environment()))
}

.with.alias <- function(df.expr) {
  exp <- df.expr
  df <- exp[[2]]
  l <- eval(bquote(attr(.(exp[[2]]), "aliases")), env = parent.env(environment()))
  eval(bquote(substitute(.(exp), l)))
} 

with.alias <- function(df.expr) {
  exp <- substitute(df.expr)
  l <- eval(bquote(attr(.(exp[[2]]), "aliases")), env = parent.env(environment()))
  if (exp[[1]] == "<-") {
    l <- eval(bquote(attr(.(exp[[2]][[2]]), "aliases")), env = parent.env(environment()))
    eval(eval(bquote(substitute(.(.with.alias(exp[[2]])) <- .(exp[[3]])))), env = parent.env(environment()))
  } else {
    df <- exp[[2]]
    eval(eval(bquote(substitute(.(exp), l))), env = parent.env(environment()))
  }
} # that's it! works!

Совет: вы можете сэкономить на вводе, определив:

# make `with.aliases` shorter:
a <- with.aliases

## and now:
a(df$TPT) # works, too!

Что ж, но мне нужно еще поработать над методами '<-'. Однако простое назначение в a работает.

a(df$TPT <- new.vetor)  # assigns correctly
a(df$TPT[3] <- 3)       # but this not yet ...

Если вы используете data.table, тогда есть встроенный псевдоним. Вы можете

  • Используйте data.table
  • Создайте список исходных имен столбцов
  • Измените нужные вам столбцы, это будет просто указатель, а не копия.
  • Подключите эту таблицу к своим функциям.
  • Поменять имена обратно.
a <- data.table::as.data.table(survival::bladder)
originalNames <- data.table::copy(names(a))   # Create a copy of the original names
originalNames
b <- a  # Allias the data.table.  Not really needed.
data.table::setnames(b, old = 'event', new = "LBTPT")
dplyr::glimpse(b)  #  names in both data tables are changed
dplyr::glimpse(a)  #  names in both data tables are changed
data.table::setnames(a, old = names(b), new = originalNames)  # Change back to old names when you are done
dplyr::glimpse(a)  # Back to original

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

Bill Denney 22.08.2019 20:13

Мой метод выполняет две вещи, которых нет у принятого метода. Люди, читающие ваш код, увидят setnames и поймут изменение имен столбцов. Во-вторых, нет необходимости изучать методы R6. Кроме того, мой метод по-прежнему позволяет использовать код, который ссылается на столбцы с двумя разными именами, не имея двух копий данных. Ответ, который вы приняли, сделает ваш код очень трудным для понимания другим программистом.

Harlan Nelson 22.08.2019 22:37

Другие вопросы по теме