При написании пакета R, используя функцию flowCore :: transform, могу ли я использовать имя переменной в качестве текста и получить фактическое значение? - PullRequest
5 голосов
/ 13 марта 2020

Я пытаюсь передать аргумент функции, которая является строкой, но должна быть оценена как по имени (символу?), Так и по значению (см. Пример ниже). Пока что я могу использовать base::get для получения фактического значения, но назначение в flowCore::'transform,flowSet-method' завершается неудачно. Я знаю, что многие вопросы по SO касаются оценки строк как имен переменных, и, как вы увидите ниже, я перепробовал множество из них. Я предполагаю, что должен быть ответ на основе rlang, но я не могу найти какое-либо решение, приветствуются любые указатели.

Воспроизводимый пример:

# load required packages -------------------------------------------------------
library(flowAI)   # Bioconductor
library(flowCore) # Bioconductor
library(rlang)
# load example data ------------------------------------------------------------
data(Bcells) # from flowAI
# reprex -----------------------------------------------------------------------
timeCh <- "Time" # this could be variable

x <- flowCore::transform(Bcells,`Time`=(`Time`-min(`Time`)))           # this works
y <- flowCore::transform(Bcells,`Time`=(get(timeCh)-min(get(timeCh)))) # still good
z <- flowCore::transform(Bcells,timeCh=(get(timeCh)-min(get(timeCh)))) # not good

Хотя в приведенном выше коде transform for z будет работать просто отлично, фактически в flowSet добавлен новый столбец с именем timeCh. Это нежелательный эффект, потому что я хочу использовать преобразование, чтобы специально изменить существующий столбец Time. Поэтому я пробовал несколько стратегий, чтобы вычислить строку, хранящуюся в timeCh, как имя объекта (?) В transform, но безрезультатно:

timeSym <- sym("Time")
timequo <- quo(timeCh)

t1 <- flowCore::transform(Bcells,!!timeSym=(get(timeCh)-min(get(timeCh)))) 
# Error: unexpected '=' in "t1 <- flowCore::transform(Bcells,!!timeSym="
t2 <- flowCore::transform(Bcells,{{timeSym}}=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t2 <- flowCore::transform(Bcells,{{timeSym}}="
t3 <-  flowCore::transform(Bcells,eval(parse(text=timeCh))=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t3 <-  flowCore::transform(Bcells,eval(parse(text=timeCh))="
t4 <-  flowCore::transform(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh)))))
# Error in get(timeCh) : object 'Time' not found
t5 <-  flowCore::transform(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh))),inherits = TRUE))
# Error in get(timeCh) : object 'Time' not found
t6 <-  flowCore::transform(Bcells,with(Bcells,assign(timeCh,(get(timeCh)-min(get(timeCh))),inherits = TRUE)))
# Error in get(timeCh) : object 'Time' not found
t7 <-  flowCore::transform(Bcells,as.name(timeCh)=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t7 <-  flowCore::transform(Bcells,as.name(timeCh)="
t8 <-  flowCore::transform(Bcells,UQ(timequo)=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t8 <-  flowCore::transform(Bcells,UQ(timequo)="
t9 <-  flowCore::transform(Bcells,(eval(quote(timeCh)))=(get(timeCh)-min(get(timeCh))))
# Error: unexpected '=' in "t9 <-  flowCore::transform(Bcells,(eval(quote(timeCh)))="

Мне кажется, проблема с областью видимости , но я действительно озадачен тем, как обойти это.

Ответы [ 2 ]

5 голосов
/ 17 марта 2020

Один из возможных способов использования rlang арифметического выражения c:

# Compose the expression `Time = Time - min(Time)`
tfarg <- rlang::exprs( !!timeSym := !!timeSym - min(!!timeSym) )

# Compose the expression `flowCore::transform(Bcells, Time = Time - min(Time))`
xpr  <- rlang::expr( flowCore::transform(Bcells, !!!tfarg) )
xpr2 <- rlang::call2( flowCore::transform, Bcells, !!!tfarg )   # Alternative

# Evaluate the second expression
t1 <- eval(xpr)      # or t1 <- eval(xpr2)

# Compare to desired output
identical( summary(t1), summary(x) )  # TRUE

В приведенном выше примере мы сначала создаем выражение Time = Time - min(Time) с использованием квазиквотация . Думайте об этом как о замене !!timeSym символом, хранящимся внутри timeSym (то есть, Time), при использовании :=, чтобы заставить его работать в левой части назначения.

Мы затем создайте второе выражение flowCore::transform(Bcells, Time = Time - min(Time)), вставив первое выражение в вызов функции flowCore::transform(). Наконец, мы оцениваем его и сравниваем результат с желаемым результатом.

Примечание: похоже, что минимальное значение времени равно нулю, поэтому ваш transform() фактически ничего не делает.

4 голосов
/ 17 марта 2020

Похоже, эта функция в основном имитирует base::transform и ее нестандартную оценку. Это означает, что я могу использовать это как MRE:

expectedresult <- transform(airquality, Ozone = Ozone - min(Ozone))

Сначала мы переписываем это, используя do.call:

all.equal(
  do.call(transform, list(`_data` = airquality, Ozone = quote(Ozone - min(Ozone))))
  ,expectedresult)
#[1] TRUE

Отлично, теперь мы можем установить имена списков программно и подставить в выражение в кавычках:

varname <- "Ozone"
varsymbol <- as.name(varname)

all.equal(
  do.call(transform, 
          setNames(list(airquality, bquote(.(varsymbol) - min(.(varsymbol)))), 
                   c("_data", varname)))
  ,expectedresult)
#[1] TRUE

Позвольте мне закончить sh с некоторыми советами:

Старайтесь избегать вспомогательных функций, которые полагаются на нестандартную оценку, если они делают такую ​​гимнастику необходимой в вашем коде .

...