在使用flowCore :: transform函数编写R程序包时,我是否都可以将变量名用作文本并获取实际值?

问题描述 投票:0回答:2

我正在尝试将参数传递给一个函数,该参数是一个字符串,但必须同时对其名称(符号?)和值进行评估(请参见下面的示例)。到目前为止,我可以使用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

虽然在上面的代码中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)))="

在我看来,范围界定是一个问题,但我真的对如何解决它感到困惑。

r bioconductor scoping rlang quosure
2个回答
0
投票
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

让我完成一些建议:

如果在代码中使此类功能成为必需,请避免使用依赖于非标准评估的便捷功能。

0
投票
# Compose the expression(s) tfarg <- rlang::exprs( !!timeSym := !!timeSym - min(!!timeSym) ) xpr <- rlang::expr( flowCore::transform(Bcells, !!!tfarg) ) # flowCore::transform(Bcells, Time = Time - min(Time)) # Evaluate the expression t1 <- eval(xpr) # Compare to "ground truth" identical( summary(t1), summary(x) ) # TRUE

[在上文中,我们首先使用Time = Time - min(Time)创建quasiquotation未求值的表达式,该表达式将!!timeSym有效地替换为timeSym中存储的符号(即Time),并且需要:=才能使它起作用在作业的左侧。

然后我们将第一个表达式粘贴到flowCore::transform(Bcells, Time = Time - min(Time))函数调用中,从而创建第二个未赋值的表达式flowCore::transform()。>

旁注:

看来最小时间值为零,所以您的transform()实际上什么也不做。
© www.soinside.com 2019 - 2024. All rights reserved.